#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import commands
import datetime
import time
import os
import gst
#import vlc    #vlc
import gdata.youtube
import gdata.youtube.service
import threading
import logging
import logging.config
import traceback
import gc
import sqlite3
import random # モジュールのインポート
import glib
import select
import cairo
from subprocess import Popen, PIPE
from xml.dom import minidom
import base64
import codecs
import webbrowser
try:
    import pygtk
    pygtk.require("2.0")
except:
    pass
try:
    import gobject
    import gtk
except:
    sys.exit(1)

playNotify = True
playNotifyError = True
errorSkip = False   #エラー発生時のリトライを行う
try:
    import pynotify
except:
    playNotify = False
    playNotifyError = False

__VERSION__ = "1.8.0.2"

flvfile = "/tmp/mikutube.flv"
Currentflvfile = ""
WorkerDWN = None
#LOGLEVEL = logging.DEBUG
LOGLEVEL = logging.INFO
OUTPUTMP3 = False
OUTPUTMP3_PATH = "/media/WINDATA/Data/iPhone/YouTube-mp3/"
MAX_BG = 2
RETRY = 5
PLAY_RETRY = 5
YOUTUBEDL_VER="10.04"
YOUTUBEDL_OPT="--no-part "
YOUTUBEDL_OPT_LOW="--no-part --max-quality=34 "
YOUTUBEDL_EXT_OPT=""
DBPath = "~/.config/MikuTube.db"
IGNORE=open(os.devnull, 'r+')
ENGINE="MPLAYER"
GetFLVFile = False
MPLAYER_OPT = ""
OUTPUTMP4 = False
OUTPUTMP4_PATH = "/media/WINDATA/Data/iPhone/YouTube/"

glade_xml = '''<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkWindow" id="MainWindow">
    <property name="visible">True</property>
    <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SUBSTRUCTURE_MASK | GDK_SCROLL_MASK</property>
    <property name="title" translatable="yes">みくつべ♪</property>
    <property name="skip_taskbar_hint">True</property>
    <signal name="destroy" handler="on_MainWindow_destroy"/>
    <signal name="expose_event" handler="on_MainWindow_expose_event"/>
    <signal name="destroy_event" handler="on_MainWindow_destroy_event"/>
    <signal name="size_allocate" handler="on_MainWindow_size_allocate"/>
    <signal name="window_state_event" handler="on_MainWindow_window_state_event"/>
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <child>
          <object class="GtkDrawingArea" id="VideoArea">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="has_focus">True</property>
            <property name="is_focus">True</property>
            <property name="events">GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
            <signal name="expose_event" handler="on_VideoArea_expose_event"/>
            <signal name="button_press_event" handler="on_VideoArea_button_press_event"/>
            <signal name="key_press_event" handler="on_VideoArea_key_press_event"/>
          </object>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
  <object class="GtkMenu" id="CtrlMenu">
    <property name="visible">True</property>
    <child>
      <object class="GtkMenuItem" id="PM_PLAY">
        <property name="visible">True</property>
        <property name="label" translatable="yes">再生</property>
        <property name="use_underline">True</property>
        <signal name="activate" handler="on_PM_PLAY_activate"/>
      </object>
    </child>
    <child>
      <object class="GtkMenuItem" id="PM_PAUSE">
        <property name="visible">True</property>
        <property name="label" translatable="yes">一時停止</property>
        <property name="use_underline">True</property>
        <signal name="activate" handler="on_PM_PAUSE_activate"/>
      </object>
    </child>
    <child>
      <object class="GtkMenuItem" id="PM_STOP">
        <property name="visible">True</property>
        <property name="label" translatable="yes">停止</property>
        <property name="use_underline">True</property>
        <signal name="activate" handler="on_PM_STOP_activate"/>
      </object>
    </child>
    <child>
      <object class="GtkSeparatorMenuItem" id="menuitem2">
        <property name="visible">True</property>
      </object>
    </child>
    <child>
      <object class="GtkMenuItem" id="PM_PREV">
        <property name="visible">True</property>
        <property name="label" translatable="yes">前の動画</property>
        <property name="use_underline">True</property>
        <signal name="activate" handler="on_PM_PREV_activate"/>
      </object>
    </child>
    <child>
      <object class="GtkMenuItem" id="PM_NEXY">
        <property name="visible">True</property>
        <property name="label" translatable="yes">次の動画</property>
        <property name="use_underline">True</property>
        <signal name="activate" handler="on_PM_NEXY_activate"/>
      </object>
    </child>
    <child>
      <object class="GtkSeparatorMenuItem" id="menuitem1">
        <property name="visible">True</property>
      </object>
    </child>
    <child>
      <object class="GtkMenuItem" id="PM_SEARCH">
        <property name="visible">True</property>
        <property name="label" translatable="yes">プレイリスト</property>
        <property name="use_underline">True</property>
        <child type="submenu">
          <object class="GtkMenu" id="MN_SEARCH">
            <property name="visible">True</property>
            <child>
              <object class="GtkMenuItem" id="PM_KEYWORD">
                <property name="visible">True</property>
                <property name="label" translatable="yes">検索キーワードを設定</property>
                <property name="use_underline">True</property>
                <signal name="activate" handler="on_PM_KEYWORD_activate"/>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem" id="PM_RESEARCH">
                <property name="visible">True</property>
                <property name="label" translatable="yes">プレイリストを更新</property>
                <property name="use_underline">True</property>
                <signal name="activate" handler="on_PM_RESEARCH_activate"/>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem" id="PM_PLAYLIST">
                <property name="visible">True</property>
                <property name="label" translatable="yes">プレイリストの表示</property>
                <property name="use_underline">True</property>
                <signal name="activate" handler="on_PM_PLAYLIST_activate"/>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem" id="PM_PLAYLIST_SHUFFLE">
                <property name="visible">True</property>
                <property name="label" translatable="yes">プレイリストをシャッフル</property>
                <property name="use_underline">True</property>
                <signal name="activate" handler="on_PM_PLAYLIST_SHUFFLE_activate"/>
              </object>
            </child>
          </object>
        </child>
      </object>
    </child>
    <child>
      <object class="GtkSeparatorMenuItem" id="menuitem3">
        <property name="visible">True</property>
      </object>
    </child>
    <child>
      <object class="GtkCheckMenuItem" id="PM_ENABLE_PLAY">
        <property name="visible">True</property>
        <property name="label" translatable="yes">この動画を再生対象</property>
        <property name="use_underline">True</property>
        <signal name="toggled" handler="on_PM_ENABLE_PLAY_toggled"/>
      </object>
    </child>
    <child>
      <object class="GtkMenuItem" id="PM_OPTIONS">
        <property name="visible">True</property>
        <property name="label" translatable="yes">オプション</property>
        <property name="use_underline">True</property>
        <child type="submenu">
          <object class="GtkMenu" id="menu1">
            <property name="visible">True</property>
            <child>
              <object class="GtkMenuItem" id="PM_SCREENSIZE">
                <property name="visible">True</property>
                <property name="label" translatable="yes">ウィンドウの大きさ</property>
                <property name="use_underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu" id="MN_WINDOW_SIZE">
                    <property name="visible">True</property>
                    <child>
                      <object class="GtkMenuItem" id="PM_SMALL_WINDOW">
                        <property name="visible">True</property>
                        <property name="label" translatable="yes">小</property>
                        <property name="use_underline">True</property>
                        <signal name="activate" handler="on_PM_SMALL_WINDOW_activate"/>
                      </object>
                    </child>
                    <child>
                      <object class="GtkMenuItem" id="PM_NORMAL_WINDOW">
                        <property name="visible">True</property>
                        <property name="label" translatable="yes">標準</property>
                        <property name="use_underline">True</property>
                        <signal name="activate" handler="on_PM_NORMAL_WINDOW_activate"/>
                      </object>
                    </child>
                    <child>
                      <object class="GtkMenuItem" id="PM_LARGE_WINDOW">
                        <property name="visible">True</property>
                        <property name="label" translatable="yes">大</property>
                        <property name="use_underline">True</property>
                        <signal name="activate" handler="on_PM_LARGE_WINDOW_activate"/>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem" id="PM_OPTIONS_DLG">
                <property name="visible">True</property>
                <property name="label" translatable="yes">設定...</property>
                <property name="use_underline">True</property>
                <signal name="activate" handler="on_PM_OPTIONS_DLG_activate"/>
              </object>
            </child>
          </object>
        </child>
      </object>
    </child>
    <child>
      <object class="GtkSeparatorMenuItem" id="menuitem4">
        <property name="visible">True</property>
      </object>
    </child>
    <child>
      <object class="GtkMenuItem" id="PM_QUIT">
        <property name="visible">True</property>
        <property name="label" translatable="yes">終了</property>
        <property name="use_underline">True</property>
        <signal name="activate" handler="on_PM_QUIT_activate"/>
      </object>
    </child>
  </object>
</interface>
'''

dialog_xml = '''<?xml version="1.0"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkDialog" id="SearchWord">
    <property name="border_width">5</property>
    <property name="title" translatable="yes">&#x691C;&#x7D22;&#x30AD;&#x30FC;&#x30EF;&#x30FC;&#x30C9;&#x306E;&#x8A2D;&#x5B9A;</property>
    <property name="type_hint">normal</property>
    <property name="has_separator">False</property>
    <signal name="destroy" handler="on_SearchWord_destroy"/>
    <child internal-child="vbox">
      <object class="GtkVBox" id="dialog-vbox1">
        <property name="visible">True</property>
        <property name="spacing">2</property>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="label" translatable="yes">YouTube&#x306E;&#x691C;&#x7D22;&#x30AD;&#x30FC;&#x30EF;&#x30FC;&#x30C9;&#x3092;&#x8A2D;&#x5B9A;&#x3057;&#x307E;&#x3059;&#x3002;
&#x8907;&#x6570;&#x306E;&#x30AD;&#x30FC;&#x30EF;&#x30FC;&#x30C9;&#x306F;&#x534A;&#x89D2;&#x30B9;&#x30DA;&#x30FC;&#x30B9;&#x3067;&#x533A;&#x5207;&#x3063;&#x3066;&#x304F;&#x3060;&#x3055;&#x3044;&#x3002;</property>
          </object>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkComboBoxEntry" id="CMB_KEYWORD">
            <property name="visible">True</property>
            <property name="model">listKeyword</property>
            <property name="text_column">0</property>
          </object>
          <packing>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkHBox" id="hbox3">
            <property name="visible">True</property>
            <child>
              <object class="GtkVBox" id="vbox1">
                <property name="visible">True</property>
                <child>
                  <object class="GtkLabel" id="label2">
                    <property name="visible">True</property>
                    <property name="label" translatable="yes">&#x30BD;&#x30FC;&#x30C8;&#x9806;</property>
                  </object>
                  <packing>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkLabel" id="label3">
                    <property name="visible">True</property>
                    <property name="label" translatable="yes">&#x53D6;&#x5F97;&#x4EF6;&#x6570;</property>
                  </object>
                  <packing>
                    <property name="position">1</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkVBox" id="vbox2">
                <property name="visible">True</property>
                <child>
                  <object class="GtkComboBox" id="CMB_ORDER">
                    <property name="visible">True</property>
                    <property name="model">listSortOrder</property>
                  </object>
                  <packing>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkComboBox" id="CMB_LISTCOUNT">
                    <property name="visible">True</property>
                    <property name="model">listGetCount</property>
                  </object>
                  <packing>
                    <property name="position">1</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="position">3</property>
          </packing>
        </child>
        <child internal-child="action_area">
          <object class="GtkHButtonBox" id="dialog-action_area1">
            <property name="visible">True</property>
            <property name="layout_style">end</property>
            <child>
              <object class="GtkButton" id="BTN_CANCEL">
                <property name="label">gtk-cancel</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
                <signal name="clicked" handler="on_BTN_CANCEL_clicked"/>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="BTN_OK">
                <property name="label">gtk-ok</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
                <signal name="clicked" handler="on_BTN_OK_clicked"/>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
    <action-widgets>
      <action-widget response="0">BTN_CANCEL</action-widget>
      <action-widget response="0">BTN_OK</action-widget>
    </action-widgets>
  </object>
  <object class="GtkListStore" id="listSortOrder">
    <columns>
      <!-- column-name sortOrder -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row>
        <col id="0" translatable="yes">&#x95A2;&#x9023;&#x5EA6;</col>
      </row>
      <row>
        <col id="0" translatable="yes">&#x30A2;&#x30C3;&#x30D7;&#x30ED;&#x30FC;&#x30C9;&#x56DE;&#x6570;</col>
      </row>
      <row>
        <col id="0" translatable="yes">&#x518D;&#x751F;&#x56DE;&#x6570;</col>
      </row>
      <row>
        <col id="0" translatable="yes">&#x8A55;&#x4FA1;</col>
      </row>
    </data>
  </object>
  <object class="GtkListStore" id="listGetCount">
    <columns>
      <!-- column-name GetCount -->
      <column type="guint"/>
    </columns>
    <data>
      <row>
        <col id="0">100</col>
      </row>
      <row>
        <col id="0">300</col>
      </row>
      <row>
        <col id="0">500</col>
      </row>
    </data>
  </object>
  <object class="GtkListStore" id="listKeyword">
    <columns>
      <!-- column-name KEYWORD -->
      <column type="gchararray"/>
    </columns>
  </object>
</interface>
'''

playlist_xml = '''<?xml version="1.0"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkDialog" id="PlayList">
    <property name="border_width">5</property>
    <property name="title" translatable="yes">&#x30D7;&#x30EC;&#x30A4;&#x30EA;&#x30B9;&#x30C8;</property>
    <property name="type_hint">normal</property>
    <property name="has_separator">False</property>
    <child internal-child="vbox">
      <object class="GtkVBox" id="dialog-vbox1">
        <property name="visible">True</property>
        <property name="spacing">2</property>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="label" translatable="yes">&#x73FE;&#x5728;&#x306E;&#x30D7;&#x30EC;&#x30A4;&#x30EA;&#x30B9;&#x30C8;</property>
          </object>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="LB_PLAYCOUNT">
            <property name="visible">True</property>
            <property name="label" translatable="yes">8</property>
          </object>
          <packing>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkScrolledWindow" id="scrolledwindow2">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="hscrollbar_policy">automatic</property>
            <child>
              <object class="GtkTreeView" id="TV_PLAYLIST">
                <property name="width_request">320</property>
                <property name="height_request">240</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <signal name="row_activated" handler="on_TV_PLAYLIST_row_activated"/>
              </object>
            </child>
          </object>
          <packing>
            <property name="position">3</property>
          </packing>
        </child>
        <child>
          <object class="GtkHBox" id="hbox1">
            <property name="visible">True</property>
            <child>
              <object class="GtkLabel" id="label2">
                <property name="visible">True</property>
                <property name="label" translatable="yes">&#x30AD;&#x30FC;&#x30EF;&#x30FC;&#x30C9;</property>
              </object>
              <packing>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkEntry" id="TXT_KEYWORD">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="invisible_char">&#x25CF;</property>
              </object>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="BTN_FILTER">
                <property name="label" translatable="yes">&#x7D5E;&#x308A;&#x8FBC;&#x307F;</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_BTN_FILTER_clicked"/>
              </object>
              <packing>
                <property name="position">2</property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="label3">
                <property name="visible">True</property>
                <property name="label" translatable="yes">&#x3000;&#x3000;</property>
              </object>
              <packing>
                <property name="position">3</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="BTN_SHUFFLE">
                <property name="label" translatable="yes">&#x30B7;&#x30E3;&#x30C3;&#x30D5;&#x30EB;</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_BTN_SHUFFLE_clicked"/>
              </object>
              <packing>
                <property name="position">4</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="position">4</property>
          </packing>
        </child>
        <child internal-child="action_area">
          <object class="GtkHButtonBox" id="dialog-action_area1">
            <property name="visible">True</property>
            <property name="layout_style">end</property>
            <child>
              <object class="GtkButton" id="BTN_CANCEL">
                <property name="label">gtk-cancel</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
                <signal name="clicked" handler="on_BTN_CANCEL_clicked"/>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="BTN_OK">
                <property name="label">gtk-ok</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
                <signal name="clicked" handler="on_BTN_OK_clicked"/>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
    <action-widgets>
      <action-widget response="0">BTN_CANCEL</action-widget>
      <action-widget response="0">BTN_OK</action-widget>
    </action-widgets>
  </object>
</interface>
'''

options_xml = '''
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <object class="GtkAdjustment" id="adjustment1">
    <property name="upper">100</property>
    <property name="step_increment">1</property>
    <property name="page_increment">10</property>
  </object>
  <object class="GtkDialog" id="OptionDialog">
    <property name="can_focus">False</property>
    <property name="border_width">5</property>
    <property name="title" translatable="yes">みくつべ♪設定</property>
    <property name="default_width">320</property>
    <property name="type_hint">normal</property>
    <child internal-child="vbox">
      <object class="GtkBox" id="dialog-vbox1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="spacing">2</property>
        <child internal-child="action_area">
          <object class="GtkButtonBox" id="dialog-action_area1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="layout_style">end</property>
            <child>
              <object class="GtkButton" id="BTN_OK">
                <property name="label">gtk-ok</property>
                <property name="use_action_appearance">False</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_action_appearance">False</property>
                <property name="use_stock">True</property>
                <signal name="clicked" handler="on_BTN_OK_clicked" swapped="no"/>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="BTN_CANCEL">
                <property name="label">gtk-cancel</property>
                <property name="use_action_appearance">False</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_action_appearance">False</property>
                <property name="use_stock">True</property>
                <signal name="clicked" handler="on_BTN_CANCEL_clicked" swapped="no"/>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkVBox" id="vbox1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkLabel" id="label1">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">みくつべ♪の各種設定を行います。</property>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="LB_VERSION">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="xalign">1</property>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkNotebook" id="notebook1">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <child>
                  <object class="GtkVBox" id="vbox2">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkCheckButton" id="CB_SHUFFLE">
                        <property name="label" translatable="yes">プレイリストのシャッフルを有効にする</property>
                        <property name="use_action_appearance">False</property>
                        <property name="width_request">300</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">False</property>
                        <property name="has_tooltip">True</property>
                        <property name="tooltip_text" translatable="yes">右クリックメニューのプレイリストのシャッフル機能を有効にします。
※チェックしただけではシャッフルされません。</property>
                        <property name="use_action_appearance">False</property>
                        <property name="draw_indicator">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkCheckButton" id="CB_ONTOP">
                        <property name="label" translatable="yes">再生ウィンドウを常に前面に</property>
                        <property name="use_action_appearance">False</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">False</property>
                        <property name="use_action_appearance">False</property>
                        <property name="draw_indicator">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">1</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkCheckButton" id="CB_HD">
                        <property name="label" translatable="yes">HD画質を使用する（あれば）</property>
                        <property name="use_action_appearance">False</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">False</property>
                        <property name="has_tooltip">True</property>
                        <property name="tooltip_text" translatable="yes">YouTubeから動画を取得する際、HD画質の動画がある場合には、HD画質動画を再生します。</property>
                        <property name="use_action_appearance">False</property>
                        <property name="draw_indicator">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">2</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkCheckButton" id="CB_USE_OSD">
                        <property name="label" translatable="yes">OSDによる曲名表示を行う</property>
                        <property name="use_action_appearance">False</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">False</property>
                        <property name="use_action_appearance">False</property>
                        <property name="draw_indicator">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">3</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkCheckButton" id="CB_USE_OSDERR">
                        <property name="label" translatable="yes">エラー発生時にOSD表示を行う</property>
                        <property name="use_action_appearance">False</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">False</property>
                        <property name="has_tooltip">True</property>
                        <property name="tooltip_text" translatable="yes">エラー発生時の通知をOSDに行うかどうかを設定します。
チェックが付いてない場合には、エラーはログにのみ記録されます。</property>
                        <property name="use_action_appearance">False</property>
                        <property name="draw_indicator">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">4</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkCheckButton" id="CB_ERR_SKIP">
                        <property name="label" translatable="yes">再生時のエラーリトライを行わない</property>
                        <property name="use_action_appearance">False</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">False</property>
                        <property name="use_action_appearance">False</property>
                        <property name="draw_indicator">True</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">5</property>
                      </packing>
                    </child>
                  </object>
                </child>
                <child type="tab">
                  <object class="GtkLabel" id="label6">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="label" translatable="yes">動作設定</property>
                  </object>
                  <packing>
                    <property name="tab_fill">False</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkVBox" id="vbox4">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkHBox" id="hbox1">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <child>
                          <object class="GtkLabel" id="label3">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="xalign">0</property>
                            <property name="label" translatable="yes">動画エンジンの選択</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">0</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkComboBox" id="DL_SELECT_ENGINE">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="has_tooltip">True</property>
                            <property name="model">listEngine</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="padding">8</property>
                            <property name="position">1</property>
                          </packing>
                        </child>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkLabel" id="label5">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="xalign">0</property>
                        <property name="label" translatable="yes">※次回起動時から有効</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="padding">2</property>
                        <property name="position">1</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkHBox" id="hbox2">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <child>
                          <object class="GtkLabel" id="label2">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="xalign">0</property>
                            <property name="label" translatable="yes">MPlayer追加オプション</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">0</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkEntry" id="TXT_MPLAYER_OPT">
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="invisible_char">●</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">1</property>
                          </packing>
                        </child>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">2</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkLabel" id="label4">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="xalign">0</property>
                        <property name="label" translatable="yes">※動画エンジンでMPLAYERを選択した場合のみ有効。
「;」で区切って複数のオプションを指定することが可能です。</property>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">3</property>
                      </packing>
                    </child>
                  </object>
                  <packing>
                    <property name="position">1</property>
                  </packing>
                </child>
                <child type="tab">
                  <object class="GtkLabel" id="label7">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="label" translatable="yes">動画再生</property>
                  </object>
                  <packing>
                    <property name="position">1</property>
                    <property name="tab_fill">False</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkVBox" id="vbox3">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkHBox" id="hbox3">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <child>
                          <object class="GtkLabel" id="label9">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="xalign">0</property>
                            <property name="label" translatable="yes">動画取得待ち時間（秒）</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">0</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkSpinButton" id="SPB_YOUTUBE_DL_TIMEOUT">
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="invisible_char">●</property>
                            <property name="xalign">1</property>
                            <property name="adjustment">adjustment1</property>
                            <property name="climb_rate">1</property>
                            <property name="snap_to_ticks">True</property>
                            <property name="numeric">True</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">1</property>
                          </packing>
                        </child>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkHBox" id="hbox4">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <child>
                          <object class="GtkLabel" id="label10">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="tooltip_text" translatable="yes">youtube-dlの追加オプションを指定します。</property>
                            <property name="xalign">0</property>
                            <property name="label" translatable="yes">追加オプション</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">0</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkEntry" id="entry1">
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="invisible_char">●</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">1</property>
                          </packing>
                        </child>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">1</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkHBox" id="hbox5">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <child>
                          <object class="GtkLabel" id="label11">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="has_tooltip">True</property>
                            <property name="tooltip_markup" translatable="yes"></property>
                            <property name="tooltip_text" translatable="yes"></property>
                            <property name="xalign">0</property>
                            <property name="label" translatable="yes">youtube-dlの最新版取得</property>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">0</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkButton" id="btUpdateYouTubeDL">
                            <property name="label" translatable="yes">更新</property>
                            <property name="use_action_appearance">False</property>
                            <property name="height_request">16</property>
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="receives_default">True</property>
                            <property name="events">GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK</property>
                            <property name="valign">center</property>
                            <property name="use_action_appearance">False</property>
                            <signal name="clicked" handler="on_btUpdateYouTubeDL_clicked" swapped="no"/>
                          </object>
                          <packing>
                            <property name="expand">True</property>
                            <property name="fill">True</property>
                            <property name="position">1</property>
                          </packing>
                        </child>
                      </object>
                      <packing>
                        <property name="expand">True</property>
                        <property name="fill">True</property>
                        <property name="position">2</property>
                      </packing>
                    </child>
                  </object>
                  <packing>
                    <property name="position">2</property>
                  </packing>
                </child>
                <child type="tab">
                  <object class="GtkLabel" id="label8">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="label" translatable="yes">youtube-dl</property>
                  </object>
                  <packing>
                    <property name="position">2</property>
                    <property name="tab_fill">False</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">2</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
    <action-widgets>
      <action-widget response="0">BTN_OK</action-widget>
      <action-widget response="0">BTN_CANCEL</action-widget>
    </action-widgets>
  </object>
  <object class="GtkListStore" id="listEngine">
    <columns>
      <!-- column-name engines -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row>
        <col id="0" translatable="yes">GStreamer</col>
      </row>
      <row>
        <col id="0" translatable="yes">MPlayer</col>
      </row>
    </data>
  </object>
</interface>
'''

class ConfigXML:
    OptionList = {   "x_pos":"0",
                            "y_pos":"0",
                            "x_size":"320",
                            "y_size":"240",
                            "list":"",
                            "listTitle":"",
                            "listDuration":"",
                            "listEnable":"",
                            "playcount":"0",
                            "keyword":"初音ミク PV",
                            "volume":"100",
                            "ontop":"False",
                            "sortOrder":"2",
                            "listMaxCount":"0",
                            "useHD":"False",
                            "shuffle":"False",
                            "osderr":"True",
                            "useosd":"True",
                            "errorSkip":"False",
                            "engine":"GSTREAMER",
                            "youtube-dl":"-n",
                            "youtube-dl-option":"",
                            "youtube-dl-timeout":"30",
                            "mplayer":""}
    AppName = "MikuTube"
    ConfigPath = "/.config/MikuTube.xml"
    Options = {}    #オプション値の辞書
    domobj = None

    def __init__(self, read):
        #print "ConfigXML"
        if read == True :
            try:
                self.domobj = minidom.parse(os.path.abspath(os.path.expanduser("~") + self.ConfigPath))
                options = self.domobj.getElementsByTagName("options")
                for opt in options :
                    for op,defVal in self.OptionList.iteritems():
                        elm = opt.getElementsByTagName(op)
                        if len(elm) > 0 :
                            self.Options[op] = self.getText(elm[0].childNodes)
                        else:
                            self.Options[op] = defVal
            except:
                for op,defVal in self.OptionList.iteritems():
                    self.Options[op] = defVal

    def getText(self,nodelist):
        rc = ""
        for node in nodelist:
            if node.nodeType == node.TEXT_NODE:
                text = str(node.data)
                text = text.rstrip(" \t\n")
                text = text.lstrip(" \t\n")
                rc = rc + text
        return rc

    def GetOption(self, optName ):
        if optName == "password":
            return str(base64.b64decode(self.Options[optName]))
        else:
            try:
                return str(self.Options[optName])
            except:
                return str(self.OptionList[optName])

    def SetOption(self, optName, value ):
        if optName == "password":
            val = base64.b64encode(value)
            self.Options[optName] = val
        else:
            self.Options[optName] = value

    def Write(self):
        try:
            impl = minidom.getDOMImplementation()
            newdoc = impl.createDocument(None, self.AppName, None)
            root = newdoc.documentElement
            opts = newdoc.createElement("options")
            root.appendChild(opts)
            for op in self.OptionList.keys():
                opt = newdoc.createElement(op)
                opts.appendChild(opt)
                text = newdoc.createTextNode(str(self.Options[op]))
                opt.appendChild(text)
            file = codecs.open(os.path.abspath(os.path.expanduser("~") + self.ConfigPath), 'wb', encoding='utf-8')
            newdoc.writexml(file, '', '\t', '\n', encoding='utf-8')
        except:
            logging.error(traceback.format_exc())

class YouTubeData:

    orderType = ["relevance","published","viewCount","rating"]
    listCountBase = [2,6,10]

    def __init__(self,KeyWord,order=2,listCount=2):
        self.videoFile = []
        self.orderString = self.orderType[int(order)]
        self.listRange = self.listCountBase[int(listCount)]
        self.SearchAndPrintVideosByKeywords(KeyWord)


    def PrintEntryDetails(self,entry):
        print 'Video title: %s' % entry.media.title.text
        print 'Video published on: %s ' % entry.published.text
        print 'Video description: %s' % entry.media.description.text
        print 'Video category: %s' % entry.media.category[0].text
        print 'Video tags: %s' % entry.media.keywords.text
        print 'Video watch page: %s' % entry.media.player.url
        print 'Video flash player URL: %s' % entry.GetSwfUrl()
        print 'Video duration: %s' % entry.media.duration.seconds

        # non entry.media attributes
        #print 'Video geo location: %s' % entry.geo.location()
        #print 'Video view count: %s' % entry.statistics.view_count
        #print 'Video rating: %s' % entry.rating.average

        # show alternate formats
        for alternate_format in entry.media.content:
            if 'isDefault' not in alternate_format.extension_attributes:
                print 'Alternate format: %s | url: %s ' % (alternate_format.type,alternate_format.url)

        # show thumbnails
        for thumbnail in entry.media.thumbnail:
            print 'Thumbnail url: %s' % thumbnail.url

    def SearchAndPrintVideosByKeywords(self,list_of_search_terms):
        client = gdata.youtube.service.YouTubeService()
        query = gdata.youtube.service.YouTubeVideoQuery()

        for indexCount in range(self.listRange):
            query.vq = list_of_search_terms
            query.max_results = 50
            query.start_index = (indexCount*50) + 1
            query.racy = "exclude"
            query.format = "5"
            #query.orderby = 'relevance'
            query.orderby = self.orderString

            feed = client.YouTubeQuery(query)

            if len(feed.entry) == 0:
                break

            for entry in feed.entry:
                #self.PrintEntryDetails(entry)
                #print entry.GetSwfUrl()
                #self.videoFile.append(entry.GetSwfUrl())
                #title = entry.media.title.text.replace(" ","_")
                #self.videoFile.append(entry.media.player.url + "|" + title)
                self.videoFile.append([entry.media.player.url,
                    entry.media.title.text,
                     entry.media.duration.seconds,True])

    def GetVideoURL(self) :
        return self.videoFile

class ReadFileWorker(threading.Thread):

    def __init__(self, playList, useHD, threadCount):
        threading.Thread.__init__(self)
        self.playList = playList
        self.url = self.playList.CurrentURL()
        self.title = self.playList.CurrentTitle()
        self.useHD = useHD
        self.flvfile = flvfile + str(threadCount)
        self.count = self.playList.count
        Currentflvfile = self.flvfile
        debuglog("Currentflvfile=" + Currentflvfile)

    def run(self):
        errorFlag = ["ERROR:","Error:","error:","エラー:"]
        hangFlag = ["HANGUP","Hangup","hangup","ハングアップ","中止","中断"]
        global GetFLVFile
        GetFLVFile = True
        if self.useHD == True:
            #cmd = os.path.dirname(os.path.abspath(__file__)) + '/youtube-dlm '+YOUTUBEDL_EXT_OPT+" " + YOUTUBEDL_OPT + ' -o '+ flvfile + ' "' + self.url + '"'
            cmd = 'youtube-dl '+YOUTUBEDL_EXT_OPT+" " + YOUTUBEDL_OPT + ' -o '+ self.flvfile + ' "' + self.url + '"'
        else:
            #cmd = os.path.dirname(os.path.abspath(__file__)) + '/youtube-dlm '+YOUTUBEDL_EXT_OPT+" "  + YOUTUBEDL_OPT_LOW + ' -o '+ flvfile + ' "' + self.url + '"'
            cmd = 'youtube-dl '+YOUTUBEDL_EXT_OPT+" "  + YOUTUBEDL_OPT_LOW + ' -o '+ self.flvfile + ' "' + self.url + '"'
        debuglog(cmd + "\n")
        ret = commands.getoutput(cmd)
        debuglog(ret)
        erflg = False
        for errmsg in errorFlag:
            if ret.find(errmsg) >= 0:
                erflg = True
                break
        if erflg :
            #cmd = os.path.dirname(os.path.abspath(__file__)) + '/youtube-dl '+YOUTUBEDL_EXT_OPT+" "  + YOUTUBEDL_OPT_LOW + ' -o '+ flvfile + ' "' + self.url + '"'
            cmd = 'youtube-dl '+YOUTUBEDL_EXT_OPT+" "  + YOUTUBEDL_OPT_LOW + ' -o '+ self.flvfile + ' "' + self.url + '"'
            debuglog(cmd + "\n")
            ret = commands.getoutput(cmd)
            debuglog(ret)
        #処理は開始したがNGの場合
        hgflg = False
        for hngmsg in hangFlag:
            if ret.find(hngmsg) >= 0:
                hgflg = True
                debuglog(ret)
                debuglog("HangedUP")
                break
        if erflg or hgflg:
            GetFLVFile = False
            debuglog("FLVファイル取得失敗")

        #MP3出力
        if hgflg == False:
            if OUTPUTMP3 == True:
                t = self.title.replace(" ","_")
                cmd = 'ffmpeg -y -i '+ self.flvfile + ' -ab 128 -ar 44100 "' + OUTPUTMP3_PATH + t + '.mp3"'
                debuglog(cmd + "\n")
                ret = commands.getoutput(cmd)
                debuglog(ret)
                cmd = 'mp3gain -r -k -p "' + OUTPUTMP3_PATH + t + '.mp3"'
                debuglog(cmd + "\n")
                ret = commands.getoutput(cmd)
                debuglog(ret)
            #iPhoneVideo出力
            if OUTPUTMP4 == True:
                t = self.title.replace(" ","_")
                cmd = 'HandBrakeCLI -i '+ self.flvfile + ' -o "' + OUTPUTMP4_PATH + t + '.mp4" --preset="iPhone & iPod Touch"'
                debuglog(cmd + "\n")
                ret = commands.getoutput(cmd)
                debuglog(ret)
                cmd = 'aacgain -r -k -p "' + OUTPUTMP4_PATH + t + '.mp4"'
                debuglog(cmd + "\n")
                ret = commands.getoutput(cmd)
                debuglog(ret)

class SearchWordWnd:

    gladefile = "SearchWord.ui"

    def __init__(self,keyword, order=2, listcount=2):
        #Set the Glade file
        self.keyword = keyword
        #load the dialog from the glade file
        #self.wTree = gtk.glade.XML(self.gladefile)
        #self.wTree = gtk.glade.xml_new_from_buffer(dialog_xml,len(dialog_xml))
        self.wTree = gtk.Builder()
        #self.wTree.add_from_file(self.gladefile)
        self.wTree.add_from_string(dialog_xml)
        dic = { "on_BTN_OK_clicked" : self.on_BTN_OK_clicked,
                "on_BTN_CANCEL_clicked" : self.on_BTN_CANCEL_clicked}
        self.wTree.connect_signals(dic)
        #Get the actual dialog widget
        self.dlg = self.wTree.get_object ("SearchWord")
        self.cmbKeyword = self.wTree.get_object ("CMB_KEYWORD")
        lsKeyword = self.wTree.get_object ("listKeyword")
        self.cmbKeyword.set_model(lsKeyword)
#        cell = gtk.CellRendererText()
#        self.cmbKeyword.pack_start(cell, True)
#        self.cmbKeyword.add_attribute(cell, 'text', 0)
        self.cmbKeyword.append_text(self.keyword)
        self.cmbKeyword.set_active(0)
        keywordList = KeywordDB()
        for kw in keywordList.GetList():
            if kw[0] != self.keyword and len(kw[0]) > 0:
                self.cmbKeyword.append_text(kw[0])

        self.comboOrder = self.wTree.get_object ("CMB_ORDER")
        lsSortOrder = self.wTree.get_object ("listSortOrder")
        self.comboOrder.set_model(lsSortOrder)
        cell = gtk.CellRendererText()
        self.comboOrder.pack_start(cell, True)
        self.comboOrder.add_attribute(cell, 'text', 0)
        self.comboOrder.set_active(order)
        self.comboListCount = self.wTree.get_object ("CMB_LISTCOUNT")
        lsGetCount = self.wTree.get_object ("listGetCount")
        self.comboListCount.set_model(lsGetCount)
        cell = gtk.CellRendererText()
        self.comboListCount.pack_start(cell, True)
        self.comboListCount.add_attribute(cell, 'text', 0)
        self.comboListCount.set_active(listcount)


    def run(self):

        #run the dialog and store the response
        self.result = self.dlg.run()
        #get the value of the entry fields
        #self.keyword = self.entry.get_text()
        self.keyword = self.cmbKeyword.get_active_text()
        #検索キーワードを保存
        keywordList = KeywordDB()
        keywordList.Clear()
        keywordList.Add(self.keyword)
        model = self.cmbKeyword.get_model()
        count = 0
        for sel in range(0,len(model)):
            self.cmbKeyword.set_active(sel)
            word = self.cmbKeyword.get_active_text()
            if word != self.keyword:
                keywordList.Add(word)
                count += 1
            if count >= 5:
                break


        #we are done with the dialog, destroy it
        comboOrder = self.comboOrder.get_active()
        comboListCount = self.comboListCount.get_active()
        self.dlg.destroy()
        #イベントを回してウィンドウが消えるようにする。
        while gtk.events_pending():
            gtk.main_iteration(1)

        #return the result and the wine
        return self.result,self.keyword,comboOrder,comboListCount


    #イベントハンドラ
    def on_BTN_OK_clicked(self, widget):
        debuglog("OK")
        self.dlg.response(gtk.RESPONSE_OK)
        self.dlg.hide()

    def on_BTN_CANCEL_clicked(self, widget):
        debuglog("CANCEL")
        self.dlg.response(gtk.RESPONSE_CANCEL)
        self.dlg.hide()

    def on_quit(self, widget):
        gtk.main_quit()

class PlayListWnd:

    gladefile = "PlayList.glade"

    def __init__(self, playList,currentCount):
        #Set the Glade file
        #load the dialog from the glade file
        #self.wTree = gtk.glade.XML(self.gladefile)
        #self.wTree = gtk.glade.xml_new_from_buffer(playlist_xml,len(playlist_xml))
        self.wTree = gtk.Builder()
        self.wTree.add_from_string(playlist_xml)
        dic = { "on_TV_PLAYLIST_row_activated" : self.on_TV_PLAYLIST_row_activated,
                "on_BTN_OK_clicked" : self.on_BTN_OK_clicked,
                "on_BTN_CANCEL_clicked" : self.on_BTN_CANCEL_clicked,
                "on_BTN_FILTER_clicked" : self.on_BTN_FILTER_clicked,
                "on_BTN_SHUFFLE_clicked" : self.on_BTN_SHUFFLE_clicked}
        self.wTree.connect_signals(dic)
        #Get the actual dialog widget
        self.play = playList

        #TreeViewを設定する
        self.dlg = self.wTree.get_object ("PlayList")
        self.playListView = self.wTree.get_object ("TV_PLAYLIST")
        self.playList = gtk.ListStore(str,bool,str,str,str)
        self.playListView.set_model(self.playList)

        #Column add
        column = gtk.TreeViewColumn(u"#", gtk.CellRendererText() , text=0)
        column.set_resizable(True)
        #column.set_sort_column_id(0)
        self.playListView.append_column(column)
        self.toggle = gtk.CellRendererToggle()
        self.toggle.connect( 'toggled', self.on_toggle_toggled, self.playList)
        column = gtk.TreeViewColumn(u"", self.toggle , active=1)
        column.set_resizable(True)
        self.playListView.append_column(column)
        column = gtk.TreeViewColumn(u"動画タイトル", gtk.CellRendererText() , text=2)
        column.set_resizable(True)
        self.playListView.append_column(column)
        column = gtk.TreeViewColumn(u"時間", gtk.CellRendererText() , text=3)
        column.set_resizable(True)
        self.playListView.append_column(column)
        #column = gtk.TreeViewColumn(u"URL", gtk.CellRendererText() , text=4)
        #column.set_resizable(True)
        #self.playListView.append_column(column)


        lineNo = 1
        topPath = None
        for (u,t,d,f) in self.play.GetList():
            alltime = "%(m)d分%(s)02d秒" % {"m":int(d)/60,"s":int(d)%60}
            #SQLiteがBooleranを扱えないため、文字列で処理するためのトラップ
            iter = None
            if type(f) == str:
                iter = self.playList.append([lineNo,eval(f),t,alltime,u])
            else:
                iter = self.playList.append([lineNo,f,t,alltime,u])
            if lineNo == self.play.count:
                topPath = self.playList.get_path(iter)
            lineNo += 1

        self.count = currentCount
        self.label = self.wTree.get_object ("LB_PLAYCOUNT")
        self.label.set_text("現在再生中の動画No："+str(self.count+1))
        btnShffle = self.wTree.get_object ("BTN_SHUFFLE")
        if self.play.shuffle == True:
            btnShffle.set_sensitive(True)
        else:
            btnShffle.set_sensitive(False)
        if topPath != None:
            self.playListView.scroll_to_cell(topPath)

    def run(self):
        #run the dialog and store the response
        self.result = self.dlg.run()
        model = self.playListView.get_model()
        iter = model.get_iter_first()
        self.listEnable = []
        while iter:
            enableFlag = model.get(iter, 1)
            lineNo = model.get(iter, 0)
            self.listEnable.append((lineNo[0],enableFlag[0]))
            iter = model.iter_next(iter)  # 次が無ければNoneでループを抜ける
        #we are done with the dialog, destroy it
        self.dlg.destroy()
        #イベントを回してウィンドウが消えるようにする。
        while gtk.events_pending():
            gtk.main_iteration(1)
        #return the result and the wine
        return self.result,self.count,self.listEnable


    #イベントハンドラ
    def on_toggle_toggled( self, cell, path, model ):
        iter = model.get_iter(path)
        b = model.get_value(iter, 1)
        model.set_value(iter, 1, not b)
        return

    def on_TV_PLAYLIST_row_activated(self, widget, path, column):
        debuglog("ROW ACTIVE")
        model = self.playListView.get_model()
        iter = model.get_iter(path)
        self.count = int(model.get(iter, 0)[0])-1
        self.dlg.response(gtk.RESPONSE_OK)
        self.dlg.hide()

    def on_BTN_FILTER_clicked(self, widget):
        self.keyword = self.wTree.get_object ("TXT_KEYWORD")
        self.playList.clear()
        for (l, u,t,d,f) in self.play.Search(self.keyword.get_text()):
            alltime = "%(m)d分%(s)02d秒" % {"m":int(d)/60,"s":int(d)%60}
            #SQLiteがBooleranを扱えないため、文字列で処理するためのトラップ
            if type(f) == str:
                self.playList.append([l+1,eval(f),t,alltime,u])
            else:
                self.playList.append([l+1,f,t,alltime,u])

    def on_BTN_SHUFFLE_clicked(self,widget):
        debuglog("SHUFFLE")
        #シャッフルする
        self.play.Shuffle()
        self.play.count = 0
        self.playList.clear()
        lineNo = 1
        for (u,t,d,f) in self.play.GetList():
            alltime = "%(m)d分%(s)02d秒" % {"m":int(d)/60,"s":int(d)%60}
            #SQLiteがBooleranを扱えないため、文字列で処理するためのトラップ
            if type(f) == str:
                self.playList.append([lineNo,eval(f),t,alltime,u])
            else:
                self.playList.append([lineNo,f,t,alltime,u])
            lineNo += 1


    def on_BTN_OK_clicked(self, widget):
        debuglog("OK")
        self.dlg.response(gtk.RESPONSE_OK)
        self.dlg.hide()

    def on_BTN_CANCEL_clicked(self, widget):
        debuglog("CANCEL")
        self.dlg.response(gtk.RESPONSE_CANCEL)
        self.dlg.hide()

    def on_quit(self, widget):
        gtk.main_quit()

class OptionsWnd:

    gladefile = "Options.glade"

    def __init__(self, engine,shuffle,ontop,useHD,playNotifyError,mplayer_opt,youtube_dl_timeout,playNotify,errorSkip):
        #Set the Glade file
        #load the dialog from the glade file
        #self.wTree = gtk.glade.XML(self.gladefile)
        #self.wTree = gtk.glade.xml_new_from_buffer(options_xml,len(options_xml))
        self.wTree = gtk.Builder()
        self.wTree.add_from_string(options_xml)
        dic = { "on_btUpdateYouTubeDL_clicked" : self.on_btUpdateYouTubeDL_clicked,
                "on_BTN_OK_clicked" : self.on_BTN_OK_clicked,
                "on_BTN_CANCEL_clicked" : self.on_BTN_CANCEL_clicked}
        self.wTree.connect_signals(dic)
        #Get the actual dialog widget
        self.dlg = self.wTree.get_object ("OptionDialog")
        self.selectEngine = self.wTree.get_object ("DL_SELECT_ENGINE")
        lsEngine = self.wTree.get_object ("listEngine")
        self.selectEngine.set_model(lsEngine)
        cell = gtk.CellRendererText()
        self.selectEngine.pack_start(cell, True)
        self.selectEngine.add_attribute(cell, 'text', 0)

        self.shuffle = self.wTree.get_object ("CB_SHUFFLE")
        self.ontop = self.wTree.get_object ("CB_ONTOP")
        self.useHD = self.wTree.get_object ("CB_HD")
        self.playNotifyError = self.wTree.get_object ("CB_USE_OSDERR")
        self.playNotify = self.wTree.get_object ("CB_USE_OSD")
        self.errorSkip = self.wTree.get_object ("CB_ERR_SKIP")
        self.mplayerOpt = self.wTree.get_object ("TXT_MPLAYER_OPT")
        self.youtube_dl_timeout = self.wTree.get_object ("SPB_YOUTUBE_DL_TIMEOUT")
        self.version = self.wTree.get_object ("LB_VERSION")

        self.version.set_text("Ver."+__VERSION__)

        if engine == "MPLAYER":
            self.selectEngine.set_active(1)
        else:
            self.selectEngine.set_active(0)
        self.shuffle.set_active(shuffle)
        self.ontop.set_active(ontop)
        self.useHD.set_active(useHD)
        self.errorSkip.set_active(errorSkip)
        self.playNotifyError.set_active(playNotifyError)
        self.mplayerOpt.set_text(mplayer_opt)
        self.youtube_dl_timeout.set_value(youtube_dl_timeout)
        self.playNotify.set_active(bool(playNotify))

    def run(self):
        #run the dialog and store the response
        self.result = self.dlg.run()
        if self.selectEngine.get_active() == 0:
            engine = "GSTREAMER"
        else:
            engine = "MPLAYER"
        #we are done with the dialog, destroy it
        shuffle = self.shuffle.get_active()
        ontop = self.ontop.get_active()
        useHD = self.useHD.get_active()
        errorSkip = self.errorSkip.get_active()
        playNotifyError = self.playNotifyError.get_active()
        mplayerOpt = self.mplayerOpt.get_text()
        youtube_dl_timeout = int(self.youtube_dl_timeout.get_value())
        playNotify = self.playNotify.get_active()
        self.dlg.destroy()
        #イベントを回してウィンドウが消えるようにする。
        while gtk.events_pending():
            gtk.main_iteration(1)
        #return the result and the wine

        return   self.result,engine,\
                    shuffle,\
                    ontop,\
                    useHD,\
                    playNotifyError,\
                    mplayerOpt,\
                    youtube_dl_timeout,\
                    playNotify,\
                    errorSkip

    #イベントハンドラ
    def on_BTN_OK_clicked(self, widget):
        debuglog("OK")
        self.dlg.response(gtk.RESPONSE_OK)
        self.dlg.hide()

    def on_BTN_CANCEL_clicked(self, widget):
        debuglog("CANCEL")
        self.dlg.response(gtk.RESPONSE_CANCEL)
        self.dlg.hide()

    def on_btUpdateYouTubeDL_clicked(self, widget):
        cmd = "gksudo 'youtube-dl -U'"
        ret = commands.getoutput(cmd)
        if ret.find("up-to-date") >= 0 :
            info_dialog(self.dlg,"youtube-dlを更新しました。")

class GSTControl:
    """GStreamerコントロール"""

    on_sync_message = False

    def __init__(self,parent):
        self.parent = parent
        self.player = None
        self.gaXID = parent.gaXID
        #gc.collect()
        if len(gc.garbage) > 0 :
            debuglog(str(gc.garbage))
        self.player = gst.element_factory_make("playbin2", "player")
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.enable_sync_message_emission()
        bus.connect("sync-message::element", self.gst_on_sync_message)
        bus.connect("message", self.gst_on_message)
        self.player.set_state(gst.STATE_NULL)
        self.retry = 0
        self.playRetry = 0
        self.playRetryRestart = 0

    #GSTコントロール
    def SetMovie(self,url):
        self.player.set_property("uri", "file://"+url )

    def Play(self):
        self.player.set_state(gst.STATE_PLAYING)

    def Pause(self):
        if self.State() != "PAUSED":
            self.player.set_state(gst.STATE_PAUSED)
        else:
            self.player.set_state(gst.STATE_PLAYING)

    def Stop(self):
        self.player.set_state(gst.STATE_NULL)

    def Volume(self,vol):
        self.player.set_property("volume",float(vol)/100.0)

    def Seek(self, location):
        debuglog("SEEK:" + str(location))
        event = gst.event_new_seek( 1.0,
                            gst.FORMAT_TIME,
                            gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
                            gst.SEEK_TYPE_SET,
                            long(location) * 1000000000,
                            gst.SEEK_TYPE_NONE,
                            0)
        ret = self.player.send_event(event)
        if ret == False:
            logging.warning ("seek error :" + str(location))
        else:
            self.player.set_new_stream_time(0L)

    def State(self):
        if self.player.get_state(1)[1] == gst.STATE_PAUSED:
            return "PAUSED"
        if self.player.get_state(1)[1] == gst.STATE_PLAYING:
            return "PLAYING"
        return "STOP"

    def GetPosition(self):
        retry = 0
        roop = True
        sec = 0
        while roop:
            try:
                p_position = self.player.query_position(gst.FORMAT_TIME)[0]
                sec = p_position / 1000000000
                roop = False
            except:
                if retry < 10:
                    retry += 1
                else:
                    roop = False
        return sec

    def SetResolution(self):
        pass

    def gst_on_sync_message(self, bus, message):
        debuglog("gst_on_sync_message")
        if self.on_sync_message == False:
            self.on_sync_message = True
            try:
                if message.structure is None:
                    return
                message_name = message.structure.get_name()
                if message_name == "prepare-xwindow-id":
                    imagesink = message.src
                    imagesink.set_property("force-aspect-ratio", True)
                    gtk.gdk.threads_enter()
                    imagesink.set_xwindow_id(self.gaXID)
                    gtk.gdk.threads_leave()
            except:
                logging.error(traceback.format_exc())
                self.Stop()
                error_dialog(self.parent.mainWindow,"動画再生でエラーが発生しました。\n再度再生を行ってみてください。\n("+str(sys.exc_info())+")")
        else:
            debuglog("exit gst_on_sync_message")
        self.on_sync_message = False
        debuglog("gst_on_sync_message exit")


    #GSTイベントハンドラ
    def gst_on_message(self, bus, message):
        global GetFLVFile, WorkerDWN
        #debuglog("gst_on_message")
        t = message.type
        #debuglog(t)
        if t == gst.MESSAGE_EOS:
            self.retry = 0
            debuglog("MESSAGE_EOS")
            if GetFLVFile == False:
                #そもそも取得を失敗
                self.retry = 0
                notifyOSDError("動画再生でエラーが発生しました。\n次の動画を再生します。")
                self.parent.PlayNext()
                debuglog("MESSAGE_EOS END")
                return
            try:
                sec = 0
                try:
                    sec = self.GetPosition()
                except:
                    logging.warning("再生位置問い合わせで例外発生")
                    debuglog(traceback.format_exc())
                    self.player.Stop()
                    if self.playRetry < RETRY and  errorSkip == False :
                        notifyOSDError("再生中にエラーが発生しました。\n動画を最初から再生します。")
                        wait(2)
                        self.SetMovie( Currentflvfile )
                        self.Seek(0)
                        self.Play()
                    else:
                        notifyOSDError("再生位置問い合わせでエラーが発生しました。\n次の動画を再生します。")
                        self.parent.PlayNext()
                    debuglog("MESSAGE_EOS END")
                    return
                if self.parent.currentWorker >= len(WorkerDWN):
                    current = WorkerDWN[0].count
                else:
                    current = WorkerDWN[self.parent.currentWorker].count
                (u,title,duration,f) = self.parent.playList.Get(current)
                duration = int(duration)
                duration -= duration / 10 #一割を残して終わったら終了と見なす。
                debuglog(str(sec) + "/" + str(duration))
                if sec >= duration :
                    #正常に再生完了
                    self.parent.PlayNext()
                else:
                    #再生失敗
                    logging.warning("playRetry:"+str(self.playRetry))
                    if self.playRetry < RETRY and self.playRetryRestart < PLAY_RETRY  and  errorSkip == False :
                        logging.warning("continue")
                        self.Pause()
                        #self.Stop()
                        wait(2)
                        self.Seek(sec)
                        self.Play()
                        self.playRetry += 1
                    elif self.playRetryRestart >= PLAY_RETRY or errorSkip == True :
                        logging.warning("next clip")
                        self.Stop()
                        notifyOSDError("再生中にエラーが発生しました。\n次の動画を再生します。")
                        wait(1)
                        self.parent.PlayNext()
                    else:
                        logging.warning("retry")
                        self.Stop()
                        notifyOSDError("再生中にエラーが発生しました。\n動画を最初から再生します。")
                        wait(2)
                        self.playRetry = 0
                        self.playRetryRestart += 1
                        self.SetMovie( Currentflvfile )
                        self.Seek(0)
                        self.Play()
            except:
                logging.error(traceback.format_exc())
                self.Stop()
                error_dialog(self.parent.mainWindow,"動画再生でエラーが発生しました。\n再度再生を行ってみてください。\n("+str(sys.exc_info())+")")
            debuglog("MESSAGE_EOS END")
        elif t == gst.MESSAGE_ERROR:
            logging.warning("MESSAGE_ERROR")
            #~ if self.retry > 5:
                #~ self.Stop()
                #~ #error_dialog(self.mainWindow,"動画再生でエラーが発生しました。\n再度再生を行うか、次の動画を再生してみてください。")
                #~ self.retry = 0
                #~ notifyOSD("動画再生でエラーが発生しました。\n次の動画を再生します。")
                #~ self.parent.PlayNext()
            #~ else:
                #~ wait(2)
                #~ self.retry += 1
                #~ notifyOSD("再生中にエラーが発生しました。\n動画を最初から再生します。")
                #~ self.parent.PlayRetry()
            self.retry = 0
            notifyOSDError("動画再生でエラーが発生しました。\n次の動画を再生します。")
            self.parent.PlayNext()
            debuglog("MESSAGE_ERROR END")
        #debuglog("gst_on_message END")
    def Quit(self):
        pass

    def SetFullscreen(self,flag):
        pass


class MPlayerControl:
    """MPlayerコントロール"""

    noplayer = False

    def __init__(self,parent):
        self.parent = parent
        self.player = None
        self.gaXID = parent.gaXID
        self.retry = 0
        self.playRetry = 0
        self.playRetryRestart = 0
        self.moviePath = ""
        self.pause = False
        self.volume = 100
        self.mute = False
#        cmd = ["mplayer", '-slave', '-quiet', '-wid',str(self.gaXID),'-idle','-cache','1024',"-osdlevel","0","-zoom"," -nomouseinput","-input","nodefault-bindings:conf=/dev/null"]
        cmd = ["mplayer", '-slave', '-quiet', '-wid',str(self.gaXID),'-idle','-nocache',"-osdlevel","0","-zoom","-nojoystick","-noconsolecontrols","-nomouseinput","-input","nodefault-bindings:conf=/dev/null"]
        global MPLAYER_OPT
        addopt = reduce(lambda x,y:x+y, [x.split() for x in MPLAYER_OPT.split(";")])
        cmd += addopt
        debuglog(str(cmd))
        self._mp = Popen(cmd,stdin=PIPE, stdout=PIPE, stderr=PIPE)
        print self._mp
        msg = []
        #FixMe Python2.7でエラーがない場合に、ここで停止する
        msg.append(self._mp.stderr.readline())
        #
        print msg
        err = [x for x in msg if x.find("could not connect to socket") < 0 ]
        faital = [x for x in msg if x.find("Unknown option on the command line") >= 0 ]
        if len(err) > 0:
            logging.error(err)
            #raise NameError(err)
        if len(faital) > 0:
            error_dialog(self.parent.mainWindow,"MPlayerに不正なオプションが指定されています。\nオプションを設定しなおしてください。\n("+faital[0]+")")
            self.noplayer = True
        self.timeout = None

    def _readlines(self):
        ret = []
        #イベントを回してウィンドウが消えるようにする。
        while any(select.select([self._mp.stdout.fileno()], [], [], 0.6)):
            ret.append( self._mp.stdout.readline() )
            while gtk.events_pending():
                gtk.main_iteration(1)
        #print ret
        return ret

    def _command(self, name, *args):
        """ Very basic interface [see populate()]
        Sends command 'name' to process, with given args
        """
        #mplayerが起動できない場合にはコマンドを実行しない
        needReadLine = ["get_time_pos","get_percent_pos","get_video_resolution"]
        if self.noplayer == True:
            return
        #イベントを回してウィンドウが消えるようにする。
        while gtk.events_pending():
            gtk.main_iteration(1)
        try:
            cmd = '%s%s%s\n'%(name,
                    ' ' if args else '',
                    ' '.join(repr(a) for a in args)
                    )
            #print cmd
            self._mp.stdin.write(cmd)
            #イベントを回してウィンドウが消えるようにする。
            while gtk.events_pending():
                gtk.main_iteration(1)
            if name == 'quit':
                return
            for c in needReadLine:
                if cmd.find(c) >= 0:
                    return self._readlines()
            return ""
        except:
            error_dialog(self.parent.mainWindow,"MPlayerとの通信が行えません。設定を確認してください。("+str(sys.exc_info())+")")

    def _setResolution(self):
#        print "_setResolution"
        try:
            reso = self._command("get_video_resolution")
            reso2 = [s for s in reso if s.find("ANS_VIDEO_RESOLUTION") >= 0]
    #        print "reso:"+str(reso2)
            resx = reso2[0].replace("\n","").split("=")[1].split("x")[0].strip("' ")
            resy = reso2[0].replace("\n","").split("=")[1].split("x")[1].strip("' ")
            rate = float(resy) / float(resx)
            ga = self.parent["VideoArea"].window
            (xsize, ysize) = self.parent.mainWindow.get_size()
            newY = int(xsize * rate)
            ofs = (ysize - newY ) / 2
            if newY <= ysize:
                ga.move_resize(0,ofs,xsize,newY)
            else:
                rate = float(resx) / float(resy)
                newX = int(ysize * rate)
                ofs = (xsize - newX ) / 2
                ga.move_resize(ofs,0, newX,ysize)
        except:
            pass

    def _checkState(self):
        """
        動画の再生状態チェック/終了していた場合には次の曲へ
        """
        global GetFLVFile
        comp = self.GetPositionPercent()
        if comp >= 80:
            self.compflag = True
        if comp >= 100:
            debuglog("MP PlayEnd")
            wait(1.0)
            self.parent.PlayNext()
            return False
        if comp == -1:
            if self.compflag == True:
                #実際にほぼ曲再生が完了していて、チェックタイミングによりエラー発生
                debuglog("MP PlayEnd")
                wait(1.0)
                self.parent.PlayNext()
                return False
            if GetFLVFile == False:
                debuglog("MP FLV Get Error")
                #flv取得失敗
                notifyOSDError("動画再生でエラーが発生しました。\n次の動画を再生します。")
                self.parent.PlayNext()
                return False
            if self.playRetryRestart >= 2 or errorSkip == True :
                notifyOSDError("動画再生でエラーが発生しました。\n次の動画を再生します。")
                self.parent.PlayNext()
                return False
            debuglog("MP Retry(" + str(self.playRetryRestart)+")")
            wait(1.0)
            self.Play()
            self.playRetryRestart += 1
        else:
            self.nowPosition = comp
        return True

    #Mplayerコントロール
    def SetMovie(self,url):
        debuglog("MP SetMovie:" + url)
        self.nowPosition = 0
        self.retry = 0
        self.playRetry = 0
        self.playRetryRestart = 0
        self.moviePath = url

    def Play(self):
        debuglog("MP Play")
        self.compflag = False
        self.pause = False
        self._command("loadfile",self.moviePath,1)
        self._setResolution()
        if self.mute == False:
            self.Volume(self.volume)
        else:
            self.Volume(0)
        if self.timeout != None:
            glib.source_remove(self.timeout)
        self.timeout = glib.timeout_add_seconds(5, self._checkState)

    def Pause(self):
        debuglog("Mplayer Pause")
        if self.pause == False:
            #一時停止
            self._command("pause")
            glib.source_remove(self.timeout)
            self.timeout = None
        else:
            #再開
            self._command("pause")
            if self.timeout != None:
                glib.source_remove(self.timeout)
            self.timeout = glib.timeout_add_seconds(5, self._checkState)
        self.pause = not self.pause

    def Stop(self):
        debuglog("MP Stop")
        self._command("stop")
        self.pause = False
        if self.timeout != None:
            glib.source_remove(self.timeout)
            self.timeout = None

    def Volume(self,vol):
        if vol > 0:
            self._command("mute",0)
            self._command("volume",vol,vol)
            self.volume = vol
            self.mute = False
        else:
            self._command("mute",1)
            self.mute = True

    def Seek(self, location):
        self._command("seek",location,2)

    def State(self):
        if self.pause == True:
            return "PAUSED"
        else:
            return "PLAYING"

    def GetPosition(self):
        ret = self._command("get_time_pos")
        ret = [s for s in ret if s.find("ANS_TIME_POSITION") >=0 ]
        if len(ret) > 0:
            tmp = ret[0].split('=')
            if len(tmp) > 0:
                sec = tmp[1].replace("\n","")
                return float(sec)
        return -1

    def GetPositionPercent(self):
        ret = self._command("get_percent_pos")
        ret = [s for s in ret if s.find("ANS_PERCENT_POSITION") >=0 ]
        if ret != None and len(ret) > 0:
            tmp = ret[0].split('=')
            if len(tmp) > 1:
                sec = tmp[1].replace("\n","")
                return float(sec)
        return -1

    def Quit(self):
        self._command("quit")

    def SetFullscreen(self,flag):
        if flag:
            self._command("set_property","fullscreen",1)
        else:
            self._command("set_property","fullscreen",0)
            self._setResolution()

    def SetResolution(self):
        self._setResolution()

class PlayList:
    """再生リストを管理します。"""

    _videoURL = []
    count = 0
    shuffle = False

    def __init__(self):
        pass

    def Add( self, url, title, duration, flag ):
        self._videoURL.append(( url, title, duration, flag ))

    def Clear(self):
        self._videoURL = []

    def Count(self):
        return len(self._videoURL)

    def GetList(self):
        return self._videoURL

    def Set(self,count,info):
        self._videoURL[count] = info

    def Get(self,count):
        return self._videoURL[count]

    def SetCurrent(self,info):
        self._videoURL[self.count] = info

    def GetCurrent(self):
        return self._videoURL[self.count]

    def CurrentURL(self):
        (u,t,d,f) = self._videoURL[self.count]
        return u

    def CurrentTitle(self):
        (u,t,d,f) = self._videoURL[self.count]
        return t

    def CurrentDuration(self):
        (u,t,d,f) = self._videoURL[self.count]
        return int(d)

    def CurrentFlag(self):
        (u,t,d,f) = self._videoURL[self.count]
        return bool(f)

    def _checkItemCount(self,count,add):
        count += add
        if count >= len(self._videoURL):
            count = 0
        if count < 0:
            count = len(self._videoURL) - 1
        return count

    def Next(self):
        flag = False
        ct = self._checkItemCount(self.count ,1)
        while bool(flag) == False:
            (u,t,d,flag) = self.Get(ct)
            if bool(flag) == True:
                self.count = ct
                break
            ct = self._checkItemCount(ct ,1)

    def Prev(self):
        flag = False
        ct = self._checkItemCount(self.count ,-1)
        while bool(flag) == False:
            (u,t,d,flag) = self.Get(ct)
            if bool(flag) == True:
                self.count = ct
                break
            ct = self._checkItemCount(ct ,-1)

    def Search(self,keyword):
        raise "このオブジェクトではサポートされていません。"

    def Shuffle(self):
        raise "このオブジェクトではサポートされていません。"


class PlayListDB:
    """再生リストを管理します。SQLite版"""

    count = 0
    shuffle = False

    def __init__(self):
        debuglog(os.path.abspath(os.path.expanduser(DBPath)))
        self.db=sqlite3.connect(os.path.abspath(os.path.expanduser(DBPath)))
        try:
            self.db.execute('create table T_PLAYLIST(id, url, title, duration, flag)')   # テーブルを作成
            self.db.execute('create table T_PLAYLIST_index(id)')
            self.db.execute('insert into T_PLAYLIST_index(id) values (-1)')
            self.db.commit()
        except:
            pass

        self.db.text_factory=str

    def Close(self):
        self.db.close();

    def Add( self, url, title, duration, flag, commit = True ):
        idx=self.db.execute('select id from T_PLAYLIST_index').fetchone()[0]+1
        self.db.execute("insert into T_PLAYLIST(id, url, title, duration, flag) values(?,?,?,?,?)", ( idx, url, title, duration, str(flag)))
        self.db.execute('update T_PLAYLIST_index set id=? where 1=1', (idx,))  # buy_index を更新します
        if commit == True:
            self.db.commit()

    def Clear(self):
        self.db.execute('delete from T_PLAYLIST')
        self.db.execute('delete from T_PLAYLIST_index')
        self.db.execute('insert into T_PLAYLIST_index(id) values (-1)')
        self.db.commit()


    def Count(self):
        idx=self.db.execute('select max(id) from T_PLAYLIST_index').fetchone()[0]+1
        return idx

    def GetList(self):
        if self._checkShuffle() == False:
            return self.db.execute('select url, title, duration, flag from T_PLAYLIST')
        else:
            return self.db.execute('select url, title, duration, flag from T_PLAYLIST,T_PLAYLIST_SHUFFLE where T_PLAYLIST.id = playid order by T_PLAYLIST_SHUFFLE.id')


    def Set(self,count,info, commit = True):
        (url, title, duration, flag) = info
        if self._checkShuffle() == False:
            self.db.execute('update T_PLAYLIST set url=?, title=?, duration=?, flag=? where id=?', (url, title, duration, str(flag), count ))
        else:
            self.db.execute('update T_PLAYLIST set url=?, title=?, duration=?, flag=? where id=(select playid from T_PLAYLIST_SHUFFLE where id=?)', (url, title, duration, str(flag), count ))
        if commit == True:
            self.db.commit()

    def Get(self,count):
        debuglog("PlayListDB.Get:" + str(count))
        if self._checkShuffle() == False:
            (u,t,d,f) = self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=?',(count,)).fetchone()
        else:
            (u,t,d,f) = self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=(select playid from T_PLAYLIST_SHUFFLE where id=?)',(count,)).fetchone()
        return (u,t,d,eval(f))

    def SetCurrent(self,info, commit = True):
        (url, title, duration, flag) = info
        if self._checkShuffle() == False:
            self.db.execute('update T_PLAYLIST set url=?, title=?, duration=?, flag=? where id=?', (url, title, duration, str(flag), self.count ))
        else:
            self.db.execute('update T_PLAYLIST set url=?, title=?, duration=?, flag=? where id=(select playid from T_PLAYLIST_SHUFFLE where id=?)', (url, title, duration, str(flag), self.count ))
        if commit == True:
            self.db.commit()

    def GetCurrent(self):
        if self._checkShuffle() == False:
            (u,t,d,f) = self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=?',(self.count,)).fetchone()
        else:
            (u,t,d,f) = self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=(select playid from T_PLAYLIST_SHUFFLE where id=?)',(self.count,)).fetchone()
        return (u,t,d,eval(f))

    def CurrentURL(self):
        if self._checkShuffle() == False:
            return self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=?',(self.count,)).fetchone()[0]
        else:
            return self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=(select playid from T_PLAYLIST_SHUFFLE where id=?)',(self.count,)).fetchone()[0]

    def CurrentTitle(self):
        if self._checkShuffle() == False:
            return self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=?',(self.count,)).fetchone()[1]
        else:
            return self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=(select playid from T_PLAYLIST_SHUFFLE where id=?)',(self.count,)).fetchone()[1]

    def CurrentDuration(self):
        if self._checkShuffle() == False:
            return int(self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=?',(self.count,)).fetchone()[2])
        else:
            return int(self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=(select playid from T_PLAYLIST_SHUFFLE where id=?)',(self.count,)).fetchone()[2])

    def CurrentFlag(self):
        if self._checkShuffle() == False:
            return eval(self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=?',(self.count,)).fetchone()[3])
        else:
            return eval(self.db.execute('select url, title, duration, flag from T_PLAYLIST where id=(select playid from T_PLAYLIST_SHUFFLE where id=?)',(self.count,)).fetchone()[3])

    def _checkItemCount(self,count,add):
        count += add
        dbCount = self.Count()
        if count >= dbCount:
            count = 0
        if count < 0:
            count = dbCount - 1
        return count

    def Next(self):
        ct = self._checkItemCount(self.count ,1)
        if self._checkShuffle() == False:
            (id,) = self.db.execute("select id from T_PLAYLIST where id>=? AND flag = 'True'",(ct,)).fetchone()
        else:
            (id,) = self.db.execute("select T_PLAYLIST_SHUFFLE.id from T_PLAYLIST,T_PLAYLIST_SHUFFLE where T_PLAYLIST.id = playid and flag = 'True' and T_PLAYLIST_SHUFFLE.id >= ? order by T_PLAYLIST_SHUFFLE.id",(ct,)).fetchone()
        self.count = int(id)

    def Prev(self):
        ct = self._checkItemCount(self.count ,-1)
        if self._checkShuffle() == False:
            (id,) = self.db.execute("select max(id) from T_PLAYLIST where id<=? AND flag = 'True'",(ct,)).fetchone()
        else:
            (id,) = self.db.execute("select max(T_PLAYLIST_SHUFFLE.id) from T_PLAYLIST,T_PLAYLIST_SHUFFLE where T_PLAYLIST.id = playid and flag = 'True' and T_PLAYLIST_SHUFFLE.id <= ? order by T_PLAYLIST_SHUFFLE.id",(ct,)).fetchone()
        self.count = int(id)

    def NextTo(self,count):
        """
        指定された曲番号の次の曲番号を返す
        """
        ct = self._checkItemCount(count ,1)
        if self._checkShuffle() == False:
            (id,) = self.db.execute("select id from T_PLAYLIST where id>=? AND flag = 'True'",(ct,)).fetchone()
        else:
            (id,) = self.db.execute("select T_PLAYLIST_SHUFFLE.id from T_PLAYLIST,T_PLAYLIST_SHUFFLE where T_PLAYLIST.id = playid and flag = 'True' and T_PLAYLIST_SHUFFLE.id >= ? order by T_PLAYLIST_SHUFFLE.id",(ct,)).fetchone()
        self.count = int(id)

    def PrevTo(self,count):
        """
        指定された曲番号の前の曲番号を返す
        """
        ct = self._checkItemCount(count ,-1)
        if self._checkShuffle() == False:
            (id,) = self.db.execute("select max(id) from T_PLAYLIST where id<=? AND flag = 'True'",(ct,)).fetchone()
        else:
            (id,) = self.db.execute("select max(T_PLAYLIST_SHUFFLE.id) from T_PLAYLIST,T_PLAYLIST_SHUFFLE where T_PLAYLIST.id = playid and flag = 'True' and T_PLAYLIST_SHUFFLE.id <= ? order by T_PLAYLIST_SHUFFLE.id",(ct,)).fetchone()
        self.count = int(id)

    def Search(self,keyword):
        debuglog( keyword )
        if len(keyword) > 0 :
            if self._checkShuffle() == False:
                return self.db.execute("select id, url, title, duration, flag from T_PLAYLIST where title Like '%"+keyword+"%'")
            else:
                return self.db.execute("select T_PLAYLIST_SHUFFLE.id, url, title, duration, flag from T_PLAYLIST,T_PLAYLIST_SHUFFLE where T_PLAYLIST.id = playid AND title Like '%"+keyword+"%' order by T_PLAYLIST_SHUFFLE.id")
        else:
            if self._checkShuffle() == False:
                return self.db.execute('select url, title, duration, flag from T_PLAYLIST')
            else:
                return self.db.execute('select T_PLAYLIST_SHUFFLE.id, url, title, duration, flag from T_PLAYLIST,T_PLAYLIST_SHUFFLE where T_PLAYLIST.id = playid order by T_PLAYLIST_SHUFFLE.id')

    def Shuffle(self):
        #テーブル作成
        try:
            self.db.execute('create table T_PLAYLIST_SHUFFLE(id,playid)')
            self.db.commit()
        except:
            pass
        #テーブル初期化
        self.db.execute('delete from T_PLAYLIST_SHUFFLE')
        random.seed()
        listCount = self.Count()
        tmp = []
        for id in range(0,listCount):
            tmp.append(id)

        for ct in range(0,listCount):
            sw = random.randint(0,listCount-1)
            tmp[sw],tmp[ct] = tmp[ct],tmp[sw]

        for id in range(0,listCount):
            self.db.execute('insert into T_PLAYLIST_SHUFFLE(id,playid) values (?,?)',(id,tmp[id]))
        self.db.commit()

    def Commit(self):
        self.db.commit()

    def _checkShuffle(self):
        #シャッフルテーブルが存在する場合には設定をみる
        try:
            sct =self.db.execute('select count(*) from T_PLAYLIST_SHUFFLE').fetchone()[0]+1
            ct =self.db.execute('select count(*) from T_PLAYLIST').fetchone()[0]+1
            if sct != ct:
                self.Shuffle()
            return self.shuffle
        except:
            #例外発生ならシャッフルは無効
            return False

class KeywordDB:
    """検索キーワードを履歴管理します"""

    def __init__(self):
        debuglog(os.path.abspath(os.path.expanduser(DBPath)))
        self.db=sqlite3.connect(os.path.abspath(os.path.expanduser(DBPath)))
        try:
            self.db.execute('create table T_KEYWORD(id, keyword)')   # テーブルを作成
            self.db.commit()
        except:
            pass

        self.db.text_factory=str

    def Close(self):
        self.db.close();

    def Add( self, keyword,commit = True ):
        idx=self.db.execute('select count(id) from T_KEYWORD').fetchone()[0]+1
        self.db.execute("insert into T_KEYWORD(id, keyword) values(?,?)", ( idx, keyword))
        if commit == True:
            self.db.commit()

    def Clear(self):
        self.db.execute('delete from T_KEYWORD')
        self.db.commit()


    def Count(self):
        idx=self.db.execute('select count(id) from T_KEYWORD').fetchone()[0]
        return idx

    def GetList(self):
        return self.db.execute('select keyword from T_KEYWORD')

    def Commit(self):
        self.db.commit()


class MikuTubeApp:
    u"""YouTubeから初音ミク関連動画を連続再生します。"""

    mainWindow = None
    context_menu = None

    gaXID = 0
    keyword = "初音ミク PV"
    drawMessage = None
    player = None
    playURL = ""
    playName = ""

    def __init__(self):
        """
        アプリケーションクラスの初期化
        """
        #ログファイルの設定
        logging.basicConfig(level=LOGLEVEL,
            format='%(asctime)s %(levelname)s %(message)s',
            filename='/tmp/mikutube.log',
            filemode='w')

        #Set the Glade file
        self.gladefile = "MikuTube.glade"
        #self.wTree = gtk.glade.XML(self.gladefile)
        #self.wTree = gtk.glade.xml_new_from_buffer(glade_xml,len(glade_xml))
        self.wTree = gtk.Builder()
        self.wTree.add_from_string(glade_xml)
        self.context_menu =  self.wTree.get_object ("CtrlMenu")
        self.watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
        self.fullscreen = False
        self.gaXID = None
        #Create our dictionary and connect it
        dic = { "on_PM_PLAY_activate" : self.on_PM_PLAY_activate,
                "on_PM_STOP_activate" : self.on_PM_STOP_activate,
                "on_PM_NEXY_activate" : self.on_PM_NEXT_activate,
                "on_PM_PREV_activate" : self.on_PM_PREV_activate,
                "on_PM_PAUSE_activate" : self.on_PM_PAUSE_activate,
                "on_PM_SMALL_WINDOW_activate" : self.on_PM_SMALL_WINDOW_activate,
                "on_PM_NORMAL_WINDOW_activate" : self.on_PM_NORMAL_WINDOW_activate,
                "on_PM_LARGE_WINDOW_activate" : self.on_PM_LARGE_WINDOW_activate,
                "on_PM_KEYWORD_activate" : self.on_PM_KEYWORD_activate,
                "on_PM_RESEARCH_activate" : self.on_PM_RESEARCH_activate,
                "on_PM_PLAYLIST_activate" : self.on_PM_PLAYLIST_activate,
                "on_PM_ENABLE_PLAY_toggled" : self.on_PM_ENABLE_PLAY_toggled,
                "on_PM_PLAYLIST_SHUFFLE_activate" : self.on_PM_PLAYLIST_SHUFFLE_activate,
                "on_PM_OPTIONS_DLG_activate" : self.on_PM_OPTIONS_DLG_activate,
                "on_PM_QUIT_activate" : self.on_quit,
                "on_VideoArea_expose_event" : self.on_VideoArea_expose_event,
                "on_VideoArea_button_press_event" : self.on_VideoArea_button_press_event,
                "on_VideoArea_key_press_event" : self.on_VideoArea_key_press_event,
                "on_MainWindow_window_state_event" : self.on_MainWindow_window_state_event,
                "on_MainWindow_expose_event" : self.on_MainWindow_expose_event,
                "on_MainWindow_size_allocate" : self.on_MainWindow_size_allocate,
                "on_MainWindow_destroy_event" : self.on_quit,
                "on_MainWindow_destroy" : self.on_quit }
        self.wTree.connect_signals(dic)


        #アプリケーションの初期化
        self.mainWindow = self.wTree.get_object ("MainWindow")
        self.mainWindow.resize(240,180)
        self.mainWindow.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))
        self["VideoArea"].set_tooltip_window(None)
        self["VideoArea"].unset_flags(gtk.DOUBLE_BUFFERED)
        self["VideoArea"].modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))

        self.setWaitCursor()
        self.playList = None
        self.mainWindowExpose = False

        #DBの存在確認データ移行時の対応
        existDB = True
        if os.path.exists(os.path.abspath(os.path.expanduser(DBPath))) == False:
            existDB = False
        #configの読み込み

        self.playList = PlayListDB()

        conf = ConfigXML(True)
        xpos = conf.GetOption("x_pos")
        ypos = conf.GetOption("y_pos")
        xsize = conf.GetOption("x_size")
        ysize = conf.GetOption("y_size")
        self.mainWindow.move(int(xpos),int(ypos))
        if int(xsize) > 10 and int(ysize) > 10 :
            self.mainWindow.resize(int(xsize),int(ysize))
        self.playList.count = int(conf.GetOption("playcount"))
        self.keyword = conf.GetOption("keyword")
        if len(self.keyword) ==0 :
            self.keyword = "初音ミク PV"
        if existDB == False:
            list = conf.GetOption("list")
            url = list.split("||")
            list = conf.GetOption("listTitle")
            title = list.split("||")
            list = conf.GetOption("listDuration")
            duration = list.split("||")
            list = conf.GetOption("listEnable")
            enable = list.split("||")
            for n in range(0,len(url)):
                u = url[n]
                t = title[n]
                d = duration[n]
                if enable[n] == "True":
                    e = True
                else:
                    e = False
                if len(u) > 0:
                    self.playList.Add(u,t,d,e)
        #音量設定
        try:
            self.volume = conf.GetOption("volume")
        except:
            self.volume = 100
        if self.volume != "":
            self.volume = int(self.volume)
        else:
            pass
        #ON TOP設定
        try:
            self.ontop = eval(conf.GetOption("ontop"))
        except:
            ontop = False
        self.mainWindow.set_keep_above(self.ontop)
        #HD画質使用
        self.useHD = eval(conf.GetOption("useHD"))
        #検索条件設定
        self.order = conf.GetOption("sortOrder")
        self.listMaxCount = conf.GetOption("listMaxCount")
        #シャッフル
        self.playList.shuffle = eval(conf.GetOption("shuffle"))

        if self.playList.Count() ==0 :
            self.readListFromYouTube()
        debuglog(self.playList.Count())
        #OSDError表示
        global playNotifyError
        try:
            playNotifyError = eval(conf.GetOption("osderr"))
        except:
            playNotifyError = True
        global playNotify
        try:
            playNotify = eval(conf.GetOption("useosd"))
        except:
            playNotify = True
        #動画エンジン設定
        global ENGINE
        ENGINE = conf.GetOption("engine")
        #mplayer option
        global MPLAYER_OPT
        MPLAYER_OPT = conf.GetOption("mplayer")
        #youtube-dl timeout
        self.youtube_dl_timeout = int(conf.GetOption("youtube-dl-timeout"))
        #YOUTUBEDL_EXT_OPT
        global YOUTUBEDL_EXT_OPT
        YOUTUBEDL_EXT_OPT = conf.GetOption("youtube-dl-option")
        if existDB == False or self.playList.Count() == 0:
            self.readListFromYouTube()
        global errorSkip
        try:
            errorSkip = eval(conf.GetOption("errorSkip"))
        except:
            errorSkip = False

        self.mute = False
        # Create Player
        #self.createGST()
        self.PlayStart()
        self.display = gtk.gdk.display_manager_get().get_default_display()
        self.clipboard = gtk.Clipboard(self.display, "CLIPBOARD")
        self.currentWorker = 0
        self.overMaxBG = False

    def __getitem__(self, key):
        """

        """
        return self.wTree.get_object (key)

    def createGST(self):
        """

        """
        if self.player == None:
            debuglog("CreateGSTControl")
            if ENGINE == "MPLAYER":
                self.player = MPlayerControl(self)
            else:
                self.player = GSTControl(self)
        if self.mute == False:
            self.player.Volume(float(self.volume))

    def readListFromYouTube(self):
        """

        """
        youTube = YouTubeData(self.keyword,self.order,self.listMaxCount)
        tmp = self.playList.shuffle
        self.playList.shuffle = False
        notPlayList = filter(lambda x: eval(x[3]) == False,self.playList.GetList())
        self.playList.shuffle = tmp
        tmpList = youTube.GetVideoURL()
        self.playList.Clear()
        for (u,t,d,f) in tmpList:
            for (nu,nt,nd,nf) in notPlayList:
                if u == nu :
                    f = nf
            self.playList.Add(u,t,d,f,False)
        self.playList.Commit()
        del tmpList
        del notPlayList
        #シャッフルが有効なら取得し直したらシャッフルもしなおす
        if self.playList.shuffle == True:
            self.playList.Shuffle()
        #print self.playList.Count()

    def stopDownload(self):
        #print "stopDownload"
        #ダウンロードプロセスを調べる
        """

        """
        cmd = " ps -A a | grep youtube-dl | grep python"
        ret = commands.getoutput(cmd)
        if ret != "" :
            lines = ret.split("\n")
            for line in lines :
                #ダウンロードプロセスをkillする
                line = line.lstrip()
                ids = line.split(" ")
                cmd = "kill -HUP " + ids[0]
                ret = commands.getoutput(cmd)
        #完全に停止するまで、ちょっと待つ
        global WorkerDWN
        while WorkerDWN != None and len(WorkerDWN) > 0 :
            wk = WorkerDWN.pop()
            debuglog(wk.flvfile)
            if os.path.exists(wk.flvfile) :
                os.remove(wk.flvfile)
            wk.join()
            del wk

    def makeToolTipString(self,osd):
        """

        """
        debuglog("makeToolTipString")
        try:
            if self.playList.Count() >= self.playList.count :
                msg = ""
                (u,title,duration,f) = self.playList.Get(self.__curWorker().count)
                if len(title) > 0 :
                    debuglog(title)
                    msg = title
                else:
                    debuglog("No Title")
                    msg = "No Title"
                msg += "\n全再生時間：%(m)d分%(s)02d秒" % {"m":(int(duration)/60),"s":(int(duration)%60)}
                msg += "\n現在の曲No："+str(self.__curWorker().count+1) +"/"+str(self.playList.Count())
                msg2 = msg
                msg += "\n音量："+str(self.volume)+"%"
                if self.mute == True:
                    msg += "(ミュート)"
                if self.fullscreen == False:
                    self["VideoArea"].set_tooltip_text(msg)
                if osd == True:
                    notifyOSD(msg2)
        except:
            logging.error(traceback.format_exc())
        debuglog("makeToolTipString END")

    def setWaitCursor(self):
        """

        """
        self.mainWindow.window.set_cursor(self.watch)
        while gtk.events_pending():
            gtk.main_iteration(1)

    def resetWaitCursor(self):
        """

        """
        self.mainWindow.window.set_cursor(None)

    def savePlayInfo(self):
        """

        """
        debuglog("savePlayInfo")
        try:
            #設定を保存
            conf = ConfigXML(False)
            (xpos, ypos) = self.mainWindow.get_position()
            (xsize, ysize) = self.mainWindow.get_size()
            conf.SetOption("x_pos",xpos)
            conf.SetOption("y_pos",ypos)
            conf.SetOption("x_size",xsize)
            conf.SetOption("y_size",ysize)
            conf.SetOption("playcount",self.__curWorker().count)
            conf.SetOption("keyword",self.keyword)
            conf.SetOption("volume",self.volume)
            conf.SetOption("ontop",self.ontop)
            conf.SetOption("sortOrder",self.order)
            conf.SetOption("listMaxCount",self.listMaxCount)
            conf.SetOption("useHD",self.useHD)
            conf.SetOption("shuffle",self.playList.shuffle)
            global playNotifyError,ENGINE
            conf.SetOption("osderr",playNotifyError)
            conf.SetOption("engine",ENGINE)
            global MPLAYER_OPT
            conf.SetOption("mplayer",MPLAYER_OPT)
            #youtube-dl timeout
            conf.SetOption("youtube-dl-timeout",self.youtube_dl_timeout)
            global playNotify
            conf.SetOption("useosd",playNotify)
            global YOUTUBEDL_EXT_OPT
            conf.SetOption("youtube-dl-option",YOUTUBEDL_EXT_OPT)
            global errorSkip
            conf.SetOption("errorSkip",errorSkip)
            #DBの存在確認データ移行時の対応
            if os.path.exists(os.path.abspath(os.path.expanduser(DBPath))) == False:
                listU = ""
                listT = ""
                listD = ""
                listE = ""
                for (url,title,duration,enable) in self.playList.GetList():
                    if len(url) > 0:
                        listU += url + "||"
                        listT += title + "||"
                        listD += str(duration) + "||"
                        listE += str(enable) + "||"
                conf.SetOption("list",listU)
                conf.SetOption("listTitle",listT)
                conf.SetOption("listDuration",listD)
                conf.SetOption("listEnable",listE)
            else:
                conf.SetOption("list","")
                conf.SetOption("listTitle","")
                conf.SetOption("listDuration","")
                conf.SetOption("listEnable","")
            conf.Write()
        except:
            logging.error(traceback.format_exc())
        debuglog("savePlayInfo END")

    def PlayNext(self):
        """
        再生の終了したファイルを削除し、次のファイルを取得する
        """
        if os.path.exists(self.currentFlv) :
            os.remove(self.currentFlv)
        self.playList.NextTo(self.__curWorker().count)
        self.PlayStart()

    def PlayRetry(self):
        """

        """
        self.PlayStart()

    def PlayStart(self):
        """

        """
        self.timeout = glib.timeout_add_seconds(1, self.TimeOut)

    def TimeOut(self):
        """

        """
        self.on_PM_PLAY_activate(self)

    def GetFLVAddress(self,url,useHD):
        """

        """
        if useHD == True:
            cmd = 'youtube-dl ' + YOUTUBEDL_OPT + ' -g "' + url + '"'
        else:
            cmd = 'youtube-dl ' + YOUTUBEDL_OPT_LOW + ' -g "' + url + '"'
        debuglog(cmd)
        ret = commands.getoutput(cmd)
        debuglog(ret)
        if YOUTUBEDL_VER == "9.10" :
            ErrorMsg = "Error: "
        else:
            ErrorMsg = "ERROR: "
        if ret.find(ErrorMsg) >= 0 :
            cmd = 'youtube-dl ' + YOUTUBEDL_OPT_LOW + ' -g "' + url + '"'
            debuglog(cmd)
            ret = commands.getoutput(cmd)
            debuglog(ret)
        return ret

    def drawWaitMessage(self):
        (xsize, ysize) = self.mainWindow.get_size()
        ctx = self["VideoArea"].window.cairo_create()
        ctx.set_source_rgba(0.0, 0.0, 0.0,0.5)
        ctx.rectangle(0,0,xsize,ysize)
        ctx.fill()

        ctx.set_source_rgb(1.0, 1.0, 1.0)
        # フォントの指定
        ctx.select_font_face('Serif', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
        ctx.set_font_size(16)
        ctx.move_to(8, 18)
        # 文字列の描画
        ctx.show_text('NOW LOADING')
        pass



    #イベントハンドラ
    def on_MainWindow_window_state_event(self, widget, event):
        debuglog("WINDOW STATE CHANGE")
        debuglog(event)
        if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
            self.mainWindow.set_skip_taskbar_hint(False)
        else:
            self.mainWindow.set_skip_taskbar_hint(True)

    def on_MainWindow_expose_event(self, widget, event):
        debuglog("MainWindow Expose")

    def on_MainWindow_size_allocate(self,widget,event):
        debuglog("MainWindow size allocate")
        if self.player != None:
            self.player.SetResolution()

    def on_quit(self, widget):
        debuglog("QUIT")
        if self.player != None:
            #演奏の中止
            self.player.Stop()
            #ダウンロード途中のファイルを中止
            self.player.Quit()
        self.stopDownload()
        self.mainWindow.hide()
        gtk.main_quit()

    #メニューイベントハンドラ
    def on_PM_SMALL_WINDOW_activate(self, widget):
        debuglog("SMALL")
        self.mainWindow.resize(160,120)

    def on_PM_NORMAL_WINDOW_activate(self, widget):
        debuglog("NORMAL")
        self.mainWindow.resize(240,180)

    def on_PM_LARGE_WINDOW_activate(self, widget):
        debuglog("LARGE")
        self.mainWindow.resize(480,360)

    def on_PM_KEYWORD_activate(self, widget):
        debuglog("KEYWORD")
        dlg = SearchWordWnd(self.keyword,int(self.order),int(self.listMaxCount))
        (ret, keyword,order,lcount ) = dlg.run()
        debuglog(ret)
        debuglog(keyword)
        if ret == gtk.RESPONSE_OK :
            self.player.Stop()
            self.keyword = keyword
            self.playList.count = 0
            self.order = order
            self.listMaxCount = lcount
            self.readListFromYouTube()
            self.PlayStart()

    def on_PM_RESEARCH_activate(self, widget):
        debuglog("RESEARCH")
        if question_dialog(self.mainWindow,"検索キーワード「"+self.keyword+"」で再検索を行います。\n再生リストは初期化されます。\n検索し直してよろしいですか？") == True :
            self.player.Stop()
            self.playList.count = 0
            self.__removeFlvTmp()
            self.setWaitCursor()
            self.readListFromYouTube()
            self.PlayStart()

    def on_PM_PLAYLIST_activate(self, widget):
        debuglog("PLAYLIST")
        global WorkerDWN
        dlg = PlayListWnd(self.playList,self.__curWorker().count)
        self.player.Pause()
        (ret, ct, enableList ) = dlg.run()
        debuglog("ret = " + str(ret))
        debuglog("ct = " + str(ct))
        debuglog("len(enableList) = " + str(len(enableList)))
        if ret == gtk.RESPONSE_OK :
            self.setWaitCursor()
            for n in range(len(enableList)):
                #debuglog( enableList[n] )
                (lineNo, ef) = enableList[n]
                (u,t,d,f) = self.playList.Get(int(lineNo)-1)
                if f != ef:
                    self.playList.Set(int(lineNo)-1, (u,t,d,ef),False)
            self.playList.Commit()
            if self.__curWorker().count != ct :
                self.player.Stop()
                self.playList.count = ct
                self.__removeFlvTmp()
                self.currentWorker = 0
                self.PlayStart()
            else:
                self.savePlayInfo()
                self.player.Pause()
            self.resetWaitCursor()
        else:
            self.player.Pause()

    def __removeFlvTmp(self):
        """
        現在のダウンロードを全て停止し、プロセスを解放する
        """
        global WorkerDWN
        self.stopDownload()
        WorkerDWN = []
        WorkerDWN = None
        self.currentWorker = 0

    def __curWorker(self):
        global WorkerDWN
        if self.currentWorker >= len(WorkerDWN):
            return WorkerDWN[0]
        return WorkerDWN[self.currentWorker]

    def on_PM_OPTIONS_DLG_activate(self,widget):
        debuglog("OPTION DIALOG")
        global ENGINE,playNotifyError,MPLAYER_OPT,playNotify,errorSkip
        dlg = OptionsWnd(ENGINE,self.playList.shuffle,self.ontop,self.useHD,playNotifyError,MPLAYER_OPT,self.youtube_dl_timeout,playNotify,errorSkip)
        (ret, eng, shuffle, ontop, useHD, notifyError,mp_opt,youtube_dl_timeout,playNotify,errorSkip) = dlg.run()
        if ret == gtk.RESPONSE_OK :
            (ENGINE, self.playList.shuffle, self.ontop, self.useHD, playNotifyError,MPLAYER_OPT,self.youtube_dl_timeout,playNotify,errorSkip) = (eng, shuffle, ontop, useHD, notifyError,mp_opt,youtube_dl_timeout,playNotify,errorSkip)
            self.mainWindow.set_keep_above(self.ontop)
            self.savePlayInfo()

    def on_PM_ENABLE_PLAY_toggled(self,widget):
        debuglog("ENABLE_MOVIE")
        b = widget.get_active()
        (u,t,d,f) = self.playList.GetCurrent()
        self.playList.SetCurrent((u,t,d,b))

    def on_PM_PLAYLIST_SHUFFLE_activate(self,widget):
        debuglog("PLAYLIST_SHUFFLE")
        #シャッフルする
        self.playList.Shuffle()
        self.playList.count = 0
        self.__removeFlvTmp()
        self.PlayStart()

    def on_PM_PLAY_activate(self,widget) :
        """

        """
        global WorkerDWN
        debuglog("PLAY")
        self.setWaitCursor()
        #self.createGST()
        if self.player != None and self.player.State() == "PAUSED":
            self.player.Play()
            self.resetWaitCursor()
        else:
            try:
                self.createGST()
                self.player.Stop()
                self.player.SetMovie("")
                self.drawMessage = self.drawWaitMessage
                self.drawMessage()
                if WorkerDWN == None :
                    #起動時の処理
                    WorkerDWN = []
                    self.currentWorker = 0
                    w = ReadFileWorker(self.playList,self.useHD,self.currentWorker)
                    w.start()
                    WorkerDWN.append(w)
                else:
                    self.currentWorker += 1
                    if self.currentWorker >= MAX_BG:
                        self.currentWorker = 0
                for n in range(0,self.youtube_dl_timeout * 2):
                    debuglog("Check Count:" + str(n))
                    if os.path.exists(self.__curWorker().flvfile) == True:
                        for m in range(0,60):
                            debuglog("Check Count2:" + str(m))
                            state = os.stat(self.__curWorker().flvfile)
                            debuglog("file size:"+str(state.st_size))
                            readsize = 1024L*512L
                            if state.st_size > readsize:
                                break
                            wait(1)
                        break
                    wait(0.5)
                menuItem = self.wTree.get_object ("PM_ENABLE_PLAY")
                (u,t,d,f) = self.playList.Get(self.__curWorker().count)
                self.playURL = u
                self.playName = t + "(" + u + ")"
                menuItem.set_active(f)
                debuglog("playList.Count() = " + str(self.__curWorker().count))
                self.makeToolTipString(True)
                debuglog("CreateToolTip Complate")
                self.savePlayInfo()
                debuglog("Profile Save Complete")
                self.resetWaitCursor()
                self.drawMessage = None
                #self.createGST()
                debuglog("currentWorker = " + str(self.currentWorker))
                self.currentFlv = self.__curWorker().flvfile
                self.player.SetMovie( self.__curWorker().flvfile )
                if self.mute == False:
                    (float(self.volume))
                self.player.Play()
                #sleep(1.0)
                debuglog("Play Start")
                #次のファイル取得
                self.playList.NextTo(self.__curWorker().count)
                nextct = self.currentWorker + 1
                if nextct >= MAX_BG:
                    nextct = 0
                    WorkerDWN = []
                w = ReadFileWorker(self.playList,self.useHD,nextct)
                w.start()
                WorkerDWN.append(w)
                debuglog("Read Next Movie")
            except:
                logging.error(traceback.format_exc())
                if self.player != None:
                    self.player.Stop()
                error_dialog(self.mainWindow,"動画再生でエラーが発生しました。\n再度再生を行ってみてください。\n("+str(sys.exc_info())+")")
        debuglog("PLAY END")

    def on_PM_STOP_activate(self,widget) :
        debuglog("STOP")
        self.player.Stop()

    def on_PM_PREV_activate(self,widget) :
        debuglog("PREV")
        ct = self.__curWorker().count
        self.__removeFlvTmp()
        self.playList.PrevTo(ct)
        self.PlayStart()

    def on_PM_NEXT_activate(self,widget) :
        debuglog("NEXT")
        ct = self.__curWorker().count
        self.__removeFlvTmp()
        self.playList.NextTo(ct)
        self.PlayStart()

    def on_PM_PAUSE_activate(self,widget) :
        debuglog("PAUSE")
        self.player.Pause()

    #DrawingAreaイベント
    def on_VideoArea_button_press_event(self, widget, event):
        debuglog("on_VideoArea_button_press_event")
        if (event.button == 3):
            #This is a right-click
            if self.playList.shuffle == False:
                self["PM_PLAYLIST_SHUFFLE"].set_sensitive(False)
            else:
                self["PM_PLAYLIST_SHUFFLE"].set_sensitive(True)
            self.context_menu.popup( None, None, None    , event.button, event.time)

    def on_VideoArea_key_press_event(self, widget, event):
        debuglog(event)
        if event.keyval == gtk.keysyms.Right :
            self.on_PM_NEXT_activate(self)
        elif event.keyval == gtk.keysyms.Left :
            self.on_PM_PREV_activate(self)
        elif event.keyval == gtk.keysyms.space :
            self.on_PM_PAUSE_activate(self)
        elif event.keyval == gtk.keysyms.Up :
            debuglog("Volume Up")
            if self.volume < 100 :
                self.volume += 10
            if self.mute == False:
                self.player.Volume(float(self.volume))
            self.makeToolTipString(False)
        elif event.keyval == gtk.keysyms.Down :
            debuglog("Volume Down")
            if self.volume > 0 :
                self.volume -= 10
            if self.mute == False:
                self.player.Volume(float(self.volume))
            self.makeToolTipString(False)
        elif event.keyval == gtk.keysyms.c :
            debuglog("url copy")
            if event.state & gtk.gdk.CONTROL_MASK:
                copystr = self.playURL
            else:
                copystr = self.playName
            self.clipboard.set_text(copystr)
        elif event.keyval == gtk.keysyms.f :
            if self.fullscreen == False :
                self.mainWindow.fullscreen()
                self["VideoArea"].set_tooltip_text("")
                if ENGINE == "MPLAYER":
                    self.player.SetFullscreen(True)
            else:
                if ENGINE == "MPLAYER":
                    self.player.SetFullscreen(False)
                self.mainWindow.unfullscreen()
            self.fullscreen = not self.fullscreen
            self.makeToolTipString(False)
        elif event.keyval == gtk.keysyms.Escape :
            if self.fullscreen == True :
                self.mainWindow.unfullscreen()
                self.fullscreen = not self.fullscreen
                self.makeToolTipString(False)
        elif event.keyval == gtk.keysyms.m :
            if self.mute == False:
                self.mute = True
                self.player.Volume(0)
            else:
                self.mute = False
                self.player.Volume(float(self.volume))
            self.makeToolTipString(False)
        elif event.keyval == gtk.keysyms.p :
            self.on_PM_PLAYLIST_activate(None)
        elif event.keyval == gtk.keysyms.s :
            debuglog("PLAYLIST_SHUFFLE")
            #シャッフルする
            self.playList.Shuffle()
            self.playList.count = 0
            self.PlayStart()
        elif event.keyval == gtk.keysyms.b :
            webbrowser.open_new_tab(self.playList.CurrentURL())
        elif event.keyval == gtk.keysyms.t :
            try:
                if self.tempontop == None:
                    self.tempontop = self.ontop
            except:
                self.tempontop = self.ontop
            ontop = self.tempontop
            if ontop == self.ontop:
                self.mainWindow.set_keep_above(not self.ontop)
                self.tempontop = not self.ontop
            else:
                self.mainWindow.set_keep_above(self.ontop)
                self.tempontop = self.ontop

    def on_VideoArea_expose_event(self, widget, event):
        debuglog(event)
        global WorkerDWN
        #再生前はデータ保存は行わない
        if WorkerDWN != None :
            if len(WorkerDWN) > 0:
                self.savePlayInfo()
        if self.gaXID == None:
            self.gaXID = self["VideoArea"].window.xid
        if self.drawMessage != None:
            self.drawMessage()

#共通汎用関数(ダイアログ・メッセージボックス等)
def notifyOSD(msg):
    if playNotify == True:
        pynotify.init("MikuTube")
        notify = pynotify.Notification("みくつべ♪",msg)
        notify.show()

def notifyOSDError(msg):
    if playNotifyError == True:
        pynotify.init("MikuTube")
        notify = pynotify.Notification("みくつべ♪",msg)
        notify.show()
    logging.error(msg.replace("\n",""))

def wait(waitTime):
    count = waitTime / 0.1
    for i in range(int(count)):
        while gtk.events_pending():
            gtk.main_iteration(1)
        time.sleep(0.1)

def sleep(sleeptime):
    limit = datetime.datetime.now() + datetime.timedelta(microseconds=sleeptime)
    while( limit < datetime.datetime.now()):
        debuglog( str(datetime.datetime.now()))
        while gtk.events_pending():
            gtk.main_iteration(1)


def debuglog(msg):
    if LOGLEVEL == logging.DEBUG:
        print msg
    logging.debug(msg)

def open_file(current_folder):
    chooserdlg = gtk.FileChooserDialog(
        title='Open file',
        action=gtk.FILE_CHOOSER_ACTION_OPEN,
        buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
    chooserdlg.set_local_only(True)
    chooserdlg.set_current_folder = current_folder
    response = chooserdlg.run()
    chooserdlg.hide()
    infile = chooserdlg.get_filename()
    chooserdlg.destroy()
    #イベントを回してウィンドウが消えるようにする。
    while gtk.events_pending():
        gtk.main_iteration(1)
    if response == gtk.RESPONSE_OK:
        return infile
    else:
        return ""

def info_dialog(pwin, msg):
    dialog = gtk.MessageDialog(
            parent = pwin,
            flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            type = gtk.MESSAGE_INFO,
            buttons = gtk.BUTTONS_OK,
            message_format = msg)
    r = dialog.run()
    dialog.hide()
    dialog.destroy()
    #イベントを回してウィンドウが消えるようにする。
    while gtk.events_pending():
        gtk.main_iteration(1)
    if r == gtk.RESPONSE_OK:
        return True
    else:
        return False

def warning_dialog(pwin, msg):
    dialog = gtk.MessageDialog(
            parent = pwin,
            flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            type = gtk.MESSAGE_WARNING,
            buttons = gtk.BUTTONS_OK,
            message_format = msg)
    r = dialog.run()
    dialog.hide()
    dialog.destroy()
    #イベントを回してウィンドウが消えるようにする。
    while gtk.events_pending():
        gtk.main_iteration(1)
    return r

def question_dialog(pwin, msg):
    dialog = gtk.MessageDialog(
            parent = pwin,
            flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            type = gtk.MESSAGE_QUESTION,
            buttons = gtk.BUTTONS_YES_NO,
            message_format = msg)
    r = dialog.run()
    dialog.hide()
    dialog.destroy()
    #イベントを回してウィンドウが消えるようにする。
    while gtk.events_pending():
        gtk.main_iteration(1)
    if r == gtk.RESPONSE_YES:
        return True
    else:
        return False

def error_dialog(pwin, msg):
    dialog = gtk.MessageDialog(
            parent = pwin,
            flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            type = gtk.MESSAGE_ERROR,
            buttons = gtk.BUTTONS_CLOSE,
            message_format = msg)
    r = dialog.run()
    dialog.hide()
    dialog.destroy()
    #イベントを回してウィンドウが消えるようにする。
    while gtk.events_pending():
        gtk.main_iteration(1)
    return r


class Splash:
    def __init__ (self):
        splashPath = ""

        if os.path.exists("/usr/share/mikutube/splash.jpg") == True:
            splashPath = "/usr/share/mikutube/splash.jpg"
        elif os.path.exists(os.path.dirname(os.path.abspath(__file__)) + "/splash.jpg") == True:
            splashPath = os.path.dirname(os.path.abspath(__file__)) + "/splash.jpg"

        if len(splashPath) > 0 :
            self.v = gtk.Window (gtk.WINDOW_TOPLEVEL)
            self.v.set_position (gtk.WIN_POS_CENTER)
            self.v.set_modal (True)
            self.v.set_size_request (320,240)
            self.v.AppPaintable = True
            self.v.set_keep_above(True)
            self.v.set_decorated(False)
            self.v.set_skip_taskbar_hint(True)

            image = gtk.Image ()
            image.set_from_file (splashPath)
            image.show ()
            self.v.add(image)
            self.v.show_all()
            self.timeout = glib.timeout_add_seconds(10, self.AutoClose)

        # MiAplicacion ()
        # self.AutoClose ()

    def AutoClose (self):
        self.v.destroy ()
        return False

if __name__ == "__main__":
    try:
        for arg in sys.argv:
            if arg == "-mplayer":
                if os.path.exists("/usr/bin/mplayer") == True:
                    ENGINE = "MPLAYER"
            if arg == "-debug":
                LOGLEVEL = logging.DEBUG

        gobject.threads_init()
        #gtk.gdk.threads_init()
        cmd = "ps -A a | grep MikuTube.py | grep python | wc -l"
        ret = commands.getoutput(cmd)
        if int(ret) > 2 :
            debuglog("みくつべ♪が起動中")
        else:
            #gc.enable()
            #gc.set_debug(gc.DEBUG_LEAK)
            splash = Splash()
            #イベントを回してウィンドウが消えるようにする。
            while gtk.events_pending():
                gtk.main_iteration(1)
            #YouTube-dlのバージョン判定
            cmd = "youtube-dl --version"
            ret = commands.getoutput(cmd)
            if ret.find("2008") >= 0 :
                #9.10のyoutube-dl
                YOUTUBEDL_OPT = "-f 22 "
                YOUTUBEDL_VER = "9.10"
            #前回起動時のテンポラリファイルをすべて削除
            ret = commands.getoutput("rm -f /tmp/mikutube.flv*")
            MikuTubeApp()
            gtk.main()
    except:
        logging.error(traceback.format_exc())
    debuglog("END_LOOP")
